用MVVM绑定WPF DataGridComboBoxColumn
我已经看过variousquestions的答案,但还没有设法将答案中的内容映射到我试图解决的问题上。我已经将它缩减为下面的代码(代表我尝试实现的结果),并且基本上希望能够在行未被编辑时呈现Person.TitleId
作为其对应的Title.TitleText
,并且具有下降正确绑定,以便它在下拉列表中显示TitleText
,并在关联的TitleId
记录更改后将其写回Person
记录。用MVVM绑定WPF DataGridComboBoxColumn
总之,我为了达到这个目的在<DataGridComboBoxColumn>
中放什么?
App.xaml.cs
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var viewModel = new ViewModels.MainWindowViewModel();
var mainWindow = new MainWindow();
mainWindow.DataContext = viewModel;
mainWindow.ShowDialog();
}
MainWindow.xaml
<Grid>
<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding Path=Contacts}">
<DataGrid.Columns>
<DataGridComboBoxColumn Header="Title" SelectedItemBinding="{Binding Person}">
<DataGridComboBoxColumn.ElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.Titles}"/>
<Setter Property="IsReadOnly" Value="True"/>
</Style>
</DataGridComboBoxColumn.ElementStyle>
<DataGridComboBoxColumn.EditingElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.Titles}"/>
<Setter Property="DisplayMemberPath" Value="TitleText" />
</Style>
</DataGridComboBoxColumn.EditingElementStyle>
</DataGridComboBoxColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
Person.cs
public class Person
{
public int TitleId { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
}
Title.cs
public struct Title
{
public Title(int titleId, string titleText)
: this()
{
TitleId = titleId;
TitleText = titleText;
}
public string TitleText { get; private set; }
public int TitleId { get; private set; }
public static List<Title> GetAvailableTitles()
{
var titles = new List<Title>();
titles.Add(new Title(1, "Mr"));
titles.Add(new Title(2, "Miss"));
titles.Add(new Title(3, "Mrs"));
return titles;
}
}
MainWindowViewModel.cs
public class MainWindowViewModel : ViewModelBase
{
private ObservableCollection<Person> contacts;
private List<Title> titles;
public MainWindowViewModel()
{
titles = Title.GetAvailableTitles();
Contacts = new ObservableCollection<Person>();
Contacts.Add(new Person() { FirstName = "Jane", LastName = "Smith", TitleId = 2 });
}
public List<Title> Titles
{
get { return titles; }
}
public ObservableCollection<Person> Contacts
{
get { return contacts; }
set
{
if (contacts != value)
{
contacts = value;
this.OnPropertyChanged("Contacts");
}
}
}
}
ViewModelBase.cs
public class ViewModelBase : INotifyPropertyChanged
{
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
这里是一个工作的代码。这里的关键是使用SelectedValueBinding
而不是SelecteItemBinding
。
<DataGridComboBoxColumn Header="Title"
SelectedValueBinding="{Binding TitleId}"
SelectedValuePath="TitleId"
DisplayMemberPath="TitleText"
>
<DataGridComboBoxColumn.ElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.Titles}"/>
</Style>
</DataGridComboBoxColumn.ElementStyle>
<DataGridComboBoxColumn.EditingElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.Titles}"/>
</Style>
</DataGridComboBoxColumn.EditingElementStyle>
</DataGridComboBoxColumn>
令人难以置信的是,我只是写了几乎完全相同的东西,好吧,这一轮去找你。 – 2011-04-01 20:20:42
这在我的简化情况下完美运行,我将花费一些时间将其整合到我的实际代码中,以查看它是否在那里工作(我确信它会!)。任何你可以解释的机会*它是如何/为什么会起作用的? :) – Rob 2011-04-01 20:36:32
'SelectedValuePath'设置选定对象中代表组合框选定项目的成员的路径,另一方面'DisplayMemberPath'设置应该显示的类内成员的路径。 “SelectedValueBinding”会将选定的值绑定到绑定中指定的属性。这有点令人困惑,但如果你使用它几次,这是有道理的。 E:http://*.com/questions/3797034/confused-with-wpf-combobox-displaymemberpath-selectedvalue-and-selectedvaluepath – 2011-04-01 20:48:59
@ SnowBear的回答对我很好。但我想澄清绑定的细节。
在@ Rob的例子中,Title和Person类都使用TitleID。 因此,在@ SnowBear的回答,在结合:
SelectedValueBinding="{Binding TitleId}"
它不是立即明显,我哪个阶级和财产的束缚。
因为SelectedValueBinding属性出现在DataGridComboBoxColumn上,所以它绑定到包含DataGrid的ItemsSource。在这种情况下,Person对象的Contacts集合。
就我而言,DataGrid的DataSource集合被赋予了一个与ComboBox的ItemSource集合的ValuePath命名不同的属性。所以我的SelectedValueBinding的值被绑定到一个不同于ComboBox的SelectedValuePath中指定的属性的属性。
如果你能概述那个“计划”的哪些部分不起作用/哪些实际上做了,它将会有所帮助。例如你能找到ComboBox的ItemsSource列表吗? – 2011-04-01 19:32:49
另外:从看起来你如何使用'Title'这个类似乎是多余的,并且最好由'Dictionary'替代。 –
2011-04-01 19:38:51
@ H.B。 - 如代码所示,网格不显示初始值的文本表示(即Person.TitleId的相应TitleText),下拉列表中正确填充{Mr,Mrs,Miss}并选择一个项目下拉式结果在TestMVVM.Models中。标题显示在网格中(TestMVVM.Models是解决方案中的名称空间,为简洁起见,我将其删除)。 – Rob 2011-04-01 19:39:26