我的ListBox
与List
DataModel
绑定。
DataModel.cs
public class DataModel
{
public string Name { get; set; }
public string Desc { get; set; }
public string Code { get; set; }
}
ListBox
应显示两个属性,因此我已将ItemTemplate
定义如下
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}"></TextBlock>
<TextBlock Text=" - "></TextBlock>
<TextBlock Text="{Binding Code}"></TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
我的要求是用户可以选择在运行时在ListBox
中显示哪两个属性。我不知道如何实现这一目标。我已经创建了一个示例解决方案来解释我的问题。
MainWindow.xaml
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" Margin="5">
<Label Content="Property One"></Label>
<ComboBox Name="ComboBox1" Margin="3" Width="150" ItemsSource="{Binding DataModelProperties}"></ComboBox>
<Label Content="Property Two"></Label>
<ComboBox Name="ComboBox2" Margin="3" Width="150" ItemsSource="{Binding DataModelProperties}"></ComboBox>
<Button Content="Go" Click="ButtonBase_OnClick" Margin="3"></Button>
</StackPanel>
<ListBox Grid.Row="1" ItemsSource="{Binding DataModelList}" Margin="5">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}"></TextBlock>
<TextBlock Text=" - "></TextBlock>
<TextBlock Text="{Binding Code}"></TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
namespace WpfApplication1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel();
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
}
}
public class ViewModel
{
public List<String> DataModelProperties { get; set; }
public List<DataModel> DataModelList { get; set; }
public ViewModel()
{
DataModelList = new List<DataModel>();
DataModelList.Add(new DataModel() { Name = "Name1", Code = "Code1", Desc = "Desc1" });
DataModelList.Add(new DataModel() { Name = "Name2", Code = "Code2", Desc = "Desc2" });
DataModelList.Add(new DataModel() { Name = "Name3", Code = "Code3", Desc = "Desc3" });
DataModelProperties = typeof(DataModel).GetProperties().Select(s => s.Name).ToList();
}
}
public class DataModel
{
public string Name { get; set; }
public string Desc { get; set; }
public string Code { get; set; }
}
}
我尝试过的事情
<TextBlock Text="{Binding ElementName=ComboBox1, Path=SelectedItem}"></TextBlock>
这只显示所选的属性名称。
答案 0 :(得分:0)
简而言之,我所做的就是将2个公共属性绑定到并将属性更改为字段。我还制作了自定义属性,以控制用户可以选择的字段。并创建了一个DisplayOptions类来存储选择并将其分布在DataModel实例中。 考虑到它是一个PoC,解决方案有点混乱,但我相信这可以做到:
XAML:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" Margin="5">
<Label Content="Property One"></Label>
<ComboBox Name="ComboBox1" Margin="3" Width="150" ItemsSource="{Binding DataModelProperties}"></ComboBox>
<Label Content="Property Two"></Label>
<ComboBox Name="ComboBox2" Margin="3" Width="150" ItemsSource="{Binding DataModelProperties}"></ComboBox>
<Button Content="Go" Click="ButtonBase_OnClick" Margin="3"></Button>
</StackPanel>
<ListBox Grid.Row="1" ItemsSource="{Binding DataModelList}" Margin="5">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding DisplayProperty1}"></TextBlock>
<TextBlock Text=" - "></TextBlock>
<TextBlock Text="{Binding DisplayProperty2}"></TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
CS:
public partial class MainWindow : Window
{
public ViewModel model = new ViewModel();
public MainWindow()
{
InitializeComponent();
DataContext = model;
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
//This part has to be on the View side, but this is PoC
model.Opts.Prop1 = typeof(DataModel).GetFields()
.Where(a => a.Name == ComboBox1.SelectedItem.ToString()).FirstOrDefault();
model.Opts.Prop2 = typeof(DataModel).GetFields()
.Where(a => a.Name == ComboBox2.SelectedItem.ToString()).FirstOrDefault();
DataContext = null;
DataContext = model;
}
}
public class ViewModel
{
public DisplayOptions Opts = new DisplayOptions();
public List<String> DataModelProperties { get; set; }
public List<DataModel> DataModelList { get; set; }
public ViewModel()
{
var properties = typeof(DataModel).GetFields()
.Where(a => a.CustomAttributes.Any(b => b.AttributeType == typeof(SwitchableAttr)));
//Initialising options before creating DataModel instances
DataModelProperties = properties.Select(s => s.Name).ToList();
Opts.Prop1 = properties.ElementAt(0);
Opts.Prop2 = properties.ElementAt(1);
DataModelList = new List<DataModel>();
DataModelList.Add(new DataModel() { Name = "Name1", Code = "Code1", Desc = "Desc1", options = Opts });
DataModelList.Add(new DataModel() { Name = "Name2", Code = "Code2", Desc = "Desc2", options = Opts });
DataModelList.Add(new DataModel() { Name = "Name3", Code = "Code3", Desc = "Desc3", options = Opts });
}
}
public class DisplayOptions
{
public FieldInfo Prop1;
public FieldInfo Prop2;
}
public class DataModel
{
public DisplayOptions options;
[SwitchableAttr]
public string Name;
[SwitchableAttr]
public string Desc;
[SwitchableAttr]
public string Code;
public string DisplayProperty1 { get { return (string)options.Prop1.GetValue(this); } set { } }
public string DisplayProperty2 { get { return (string)options.Prop2.GetValue(this); } set { } }
}
public class SwitchableAttr : Attribute { }
答案 1 :(得分:0)
我建议你管理关于&#34;动态描述的所有内容&#34;显示在ViewModel的ListBox中。
首先,您的视图模型和模型应该实现INotifyPropertyChanged。在我的示例中,我创建了一个实现它的简单基类。我的基类名为NotifyPropertyChangedImpl
。
此外,我在视图模型中添加了两个属性:用于选择属性的组合框被绑定到这两个属性。
public class ViewModel : NotifyPropertyChangedImpl
{
private string property1;
private string property2;
public List<String> DataModelProperties { get; set; }
public List<DataModel> DataModelList { get; set; }
public string Property1
{
get
{
return property1;
}
set
{
if (property1 != value)
{
property1 = value;
SetDynamicDescriptions();
}
}
}
public string Property2
{
get
{
return property2;
}
set
{
if (property2 != value)
{
property2 = value;
SetDynamicDescriptions();
}
}
}
public ViewModel()
{
DataModelList = new List<DataModel>();
DataModelList.Add(new DataModel() { Name = "Name1", Code = "Code1", Desc = "Desc1" });
DataModelList.Add(new DataModel() { Name = "Name2", Code = "Code2", Desc = "Desc2" });
DataModelList.Add(new DataModel() { Name = "Name3", Code = "Code3", Desc = "Desc3" });
DataModelProperties = typeof(DataModel).GetProperties().Select(s => s.Name).ToList();
}
private void SetDynamicDescriptions()
{
PropertyInfo propertyInfo1;
PropertyInfo propertyInfo2;
Type type = typeof(DataModel);
if (!String.IsNullOrEmpty(property1) && !String.IsNullOrEmpty(property2))
{
propertyInfo1 = type.GetProperty(property1);
propertyInfo2 = type.GetProperty(property2);
foreach (DataModel dataModel in DataModelList)
{
dataModel.DynamicDescription = String.Format("{0} - {1}",
propertyInfo1.GetValue(dataModel, null), propertyInfo2.GetValue(dataModel, null));
}
}
}
}
正如您所看到的,方法SetDynamicDescriptions
每次Property1或Property2更改时都会重建DynamicsDescription。
我还在模型类中添加了一个属性:
public class DataModel : NotifyPropertyChangedImpl
{
private string dynamicDescription;
public string Name { get; set; }
public string Desc { get; set; }
public string Code { get; set; }
public string DynamicDescription
{
get
{
return dynamicDescription;
}
set
{
if (dynamicDescription != value)
{
dynamicDescription = value;
OnPropertyChanged("DynamicDescription");
}
}
}
}
所以最后你的XAML将是:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" Margin="5">
<Label Content="Property One"></Label>
<ComboBox Name="ComboBox1" Margin="3" Width="150" ItemsSource="{Binding DataModelProperties}"
SelectedItem="{Binding Property1}"></ComboBox>
<Label Content="Property Two"></Label>
<ComboBox Name="ComboBox2" Margin="3" Width="150" ItemsSource="{Binding DataModelProperties}"
SelectedItem="{Binding Property2}"></ComboBox>
</StackPanel>
<ListBox Grid.Row="1" ItemsSource="{Binding DataModelList}" Margin="5">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding DynamicDescription}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
我希望这可以帮到你。
答案 2 :(得分:0)
这不是完整的MVVM 所以这是代码
public partial class MainWindow : Window
{
private ViewModel vm;
public MainWindow()
{
InitializeComponent();
vm = new ViewModel();
this.DataContext = vm;
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
if (!string.IsNullOrEmpty(ComboBox1.Text) && !string.IsNullOrEmpty(ComboBox2.Text))
{
vm.AddDataToModel(ComboBox1.Text, ComboBox2.Text);
}
}
}
public class ViewModel
{
public List<String> DataModelProperties { get; set; }
private ObservableCollection<DataModel> _DataModelList;
public ViewModel()
{
_DataModelList = new ObservableCollection<DataModel>();
DataModelProperties = typeof(DataModel).GetProperties().Select(s => s.Name).ToList();
}
public void AddDataToModel(string cmbx1Val,string cmbx2Val)
{
_DataModelList.Add(new DataModel() { Name = cmbx1Val, Code = cmbx2Val, Desc = "Desc1" });
}
public ObservableCollection<DataModel> DataModelList
{
get
{
return _DataModelList;
}
set
{
_DataModelList = value;
}
}
}