【发布时间】:2012-02-29 04:39:34
【问题描述】:
因为我一直在研究一个非常困难的问题:
当 ObservableCollection 内的另一个 ObservableCollection 时,DataGrid 如何正确更新 绑定到 ObservableCollection > DataGrid 是否会发生变化?
到目前为止,只有当我点击相应的单元格时,DataGrid 才会刷新。
我准备了一个完整的源代码示例来说明以下(非常简单)的情况:
有一个 ViewModel 包含一个 List。这个 List 是一个 ObservableCollection 并包含两个东西:一个整数和另一个包含四个整数的 List(又是一个 ObservableCollection)。 然后是一个有两列的 DataGrid。一列用于整数,一列用于整数列表。 这个小应用程序有按钮来修改嵌套列表中的整数,即将四个整数之一添加 +1。 GOAL 是嵌套列表的修改正在被DataGrid 反映。 到目前为止的问题是,这只发生在带有外部触发器的情况下(例如,单击相应的单元格,或单击对列进行排序的一个列标题等)
所以这里是完整的代码:
这是 DataGrid 绑定到的 ViewModel 代码:
public class ViewModel: INotifyPropertyChanged {
private Items items;
public Items Items {
get { return items; }
set {
items = value;
firePropertyChanged("Items");
}
}
public ViewModel() {
Items = new Items();
}
private void firePropertyChanged(string property) {
if (PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
public class Items: ObservableCollection<Item> {
public Items()
: base() {
this.CollectionChanged += new NotifyCollectionChangedEventHandler(OnCollectionChanged);
}
private void OnCollectionChanged(object o, NotifyCollectionChangedEventArgs e) {
if (e.NewItems != null) {
foreach (Object item in e.NewItems) {
(item as INotifyPropertyChanged).PropertyChanged += new PropertyChangedEventHandler(item_PropertyChanged);
}
}
if (e.OldItems != null) {
foreach (Object item in e.OldItems) {
(item as INotifyPropertyChanged).PropertyChanged -= new PropertyChangedEventHandler(item_PropertyChanged);
}
}
}
void item_PropertyChanged(object sender, PropertyChangedEventArgs e) {
NotifyCollectionChangedEventArgs a = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
OnCollectionChanged(a);
}
}
public class List: ObservableCollection<NumberItem> {
public List()
: base() {
this.CollectionChanged += new NotifyCollectionChangedEventHandler(OnCollectionChanged);
}
private void OnCollectionChanged(object o, NotifyCollectionChangedEventArgs e) {
if (e.NewItems != null) {
foreach (Object item in e.NewItems) {
(item as INotifyPropertyChanged).PropertyChanged += new PropertyChangedEventHandler(item_PropertyChanged);
}
}
if (e.OldItems != null) {
foreach (Object item in e.OldItems) {
(item as INotifyPropertyChanged).PropertyChanged -= new PropertyChangedEventHandler(item_PropertyChanged);
}
}
}
void item_PropertyChanged(object sender, PropertyChangedEventArgs e) {
NotifyCollectionChangedEventArgs a = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
OnCollectionChanged(a);
}
}
public class NumberItem : INotifyPropertyChanged {
private int number;
public int Number {
get { return number; }
set {
number = value;
firePropertyChanged("Number");
}
}
public NumberItem(int i) {
Number = i;
}
private void firePropertyChanged(string property) {
if (PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
public class Item : INotifyPropertyChanged {
private List list;
public List List {
get { return list; }
set {
list = value;
firePropertyChanged("List");
}
}
private int numberOne;
public int NumberOne {
get { return numberOne; }
set {
numberOne = value;
firePropertyChanged("NumberOne");
}
}
private void firePropertyChanged(string property) {
if (PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
/// <summary>
/// This converter simply transforms the list of integers into a string.
/// </summary>
public class Converter : IValueConverter {
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
List l = (List)value;
string s = "";
return s + l[0].Number + " " + l[1].Number + " " + l[2].Number + " " + l[3].Number;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
return null;
}
}
操作嵌套列表整数的按钮代码如下:
private void plus1L(object sender, RoutedEventArgs e) {
vm.Items[0].List[0].Number += 1;
}
最后,这是绑定 DataGrid 的 XAML:
<sdk:DataGrid x:Name="dg" Margin="17,139,21,0" ItemsSource="{Binding Items}" AutoGenerateColumns="False" VerticalAlignment="Top" Height="164" d:LayoutOverrides="Width, HorizontalMargin">
<sdk:DataGrid.Columns>
<sdk:DataGridTextColumn x:Name="A" Header="A" Binding="{Binding NumberOne}"/>
<sdk:DataGridTextColumn x:Name="List" Header="List" Binding="{Binding List, Converter={StaticResource Converter}}"/>
</sdk:DataGrid.Columns>
</sdk:DataGrid>*emphasized text*
【问题讨论】:
标签: wpf silverlight data-binding datagrid inotifypropertychanged