将 WPF DataGridComboBoxColumn 与 MVVM 绑定
我查看了各种问题的答案 问题,但未能将答案中的内容映射到我试图解决的问题。我已将其简化为以下代码(代表我想要实现的结果),并且基本上希望能够将 Person.TitleId
渲染为其相应的 Title。 TitleText
当未编辑该行时,并正确绑定下拉列表,以便在下拉列表中显示 TitleText
并写入关联的 TitleId< /code> 返回到发生更改时的
Person
记录。
简而言之,我应该在
中放入什么来实现此目的?
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;
}
I've looked at the answers to various questions, but haven't managed to map the content in the answers to the problem I'm attempting to solve. I've reduced it down to the following code (representative of the outcome I'm trying to achieve), and basically want to be able to render the Person.TitleId
as its corresponding Title.TitleText
when the row isn't being edited, and have the drop-down bound correctly so that it displays the TitleText
s in the drop-down and writes the associated TitleId
back to the Person
record when its changed.
In short, what do I put in my <DataGridComboBoxColumn>
to achieve this?
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;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这是一个工作代码。这里的关键点是使用
SelectedValueBinding
而不是SelecteItemBinding
。Here is a working code. The key point here was to use
SelectedValueBinding
instead ofSelecteItemBinding
.@SnowBear 的回答对我来说效果很好。但我想澄清一下绑定的细节。
在@Rob 的示例中,Title 和 Person 类都使用 TitleID。
因此,在 @SnowBear 的回答中,在绑定中:
对我来说,绑定哪个类和属性并不是很明显。
由于 SelectedValueBinding 属性出现在 DataGridComboBoxColumn 上,因此它绑定到包含 DataGrid 的 ItemsSource。在本例中是 Person 对象的 Contacts 集合。
在我的例子中,DataGrid 的 DataSource 集合的属性名称与 ComboBox 的 ItemSource 集合的 ValuePath 不同。因此,我的 SelectedValueBinding 的值绑定到与 ComboBox 的 SelectedValuePath 中命名的属性不同的属性。
@SnowBear's answer worked well for me. But I want to clarify a detail of the binding.
In @Rob's example, both Title and Person classes use TitleID.
Therefore, in @SnowBear's answer, in the binding:
it wasn't immediately obvious to me which class and property was being bound.
Because the SelectedValueBinding attribute appeared on the DataGridComboBoxColumn, it is binding to the ItemsSource of the containing DataGrid. In this case the Contacts collection of Person objects.
In my case, the DataGrid's DataSource collection was attributed with a property that was named different from the ValuePath of the ComboBox's ItemSource collection. So my SelectedValueBinding's value was bound to a different property than the property named in the ComboBox's SelectedValuePath.