问题:
- 你声明一个
ItemsControl
(或派生自的控件ItemsControl
) 在里面
看法。
- 您绑定
ItemsControl.ItemsSource
财产给ObservableCollection
在你的视图模型中。
- 当项目添加到/删除时,您的视图会按预期更新
ObservableCollection
.
- 但是,当您更改项目中项目的属性时,视图不会更新
ObservableCollection
.
背景:
看来这是很多WPF开发者都遇到过的常见问题。已经被问过好几次了:
当 Item 更改时通知 ObservableCollection https://stackoverflow.com/questions/8490533/notify-observablecollection-when-item-changes
ObservableCollection 没有注意到其中的 Item 发生变化(即使使用 INotifyPropertyChanged) https://stackoverflow.com/questions/1427471/observablecollection-not-noticing-when-item-in-it-changes-even-with-inotifyprop
ObservableCollection 和 Item PropertyChanged https://stackoverflow.com/questions/901921/observablecollection-and-item-propertychanged
我的实施:
我尝试实施已接受的解决方案当 Item 更改时通知 ObservableCollection https://stackoverflow.com/questions/8490533/notify-observablecollection-when-item-changes。基本思想是连接一个PropertyChanged
MainWindowViewModel 中每个项目的处理程序ObservableCollection
。当项目的属性更改时,将调用事件处理程序并以某种方式更新视图。
我无法让实施工作。这是我的实现。
视图模型:
class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName = "")
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
项目视图模型:
class EmployeeViewModel : ViewModelBase
{
private int _age;
private string _name;
public int Age
{
get { return _age; }
set
{
_age = value;
RaisePropertyChanged("Age");
}
}
public string Name
{
get { return _name; }
set
{
_name = value;
RaisePropertyChanged("Name");
}
}
public override string ToString()
{
return string.Format("{0} is {1} years old", Name, Age);
}
}
主窗口视图模型:
class MainWindowViewModel : ViewModelBase
{
private ObservableCollection<EmployeeViewModel> _collection;
public MainWindowViewModel()
{
_collection = new ObservableCollection<EmployeeViewModel>();
_collection.CollectionChanged += MyItemsSource_CollectionChanged;
AddEmployeeCommand = new DelegateCommand(() => AddEmployee());
IncrementEmployeeAgeCommand = new DelegateCommand(() => IncrementEmployeeAge());
}
public ObservableCollection<EmployeeViewModel> Employees
{
get { return _collection; }
}
public ICommand AddEmployeeCommand { get; set; }
public ICommand IncrementEmployeeAgeCommand { get; set; }
public void AddEmployee()
{
_collection.Add(new EmployeeViewModel()
{
Age = 1,
Name = "Random Joe",
});
}
public void IncrementEmployeeAge()
{
foreach (var item in _collection)
{
item.Age++;
}
}
private void MyItemsSource_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null)
foreach (EmployeeViewModel item in e.NewItems)
item.PropertyChanged += ItemPropertyChanged;
if (e.OldItems != null)
foreach (EmployeeViewModel item in e.OldItems)
item.PropertyChanged -= ItemPropertyChanged;
}
private void ItemPropertyChanged(object sender, PropertyChangedEventArgs e)
{
RaisePropertyChanged("Employees");
}
}
View:
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"
xmlns:d="clr-namespace:Iress.IosPlus.DynamicOE.Controls"
Title="MainWindow" Height="350" Width="350">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.3*"></ColumnDefinition>
<ColumnDefinition Width="0.7*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0">
<Button Command="{Binding AddEmployeeCommand}">Add Employee</Button>
<Button Command="{Binding IncrementEmployeeAgeCommand}">Increment Employee Age</Button>
</StackPanel>
<Grid Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="0.1*"></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="{Binding Path=Employees[0]}"></TextBlock>
<ItemsControl Grid.Row="1" ItemsSource="{Binding Path=Employees}" BorderBrush="Red" BorderThickness="1"></ItemsControl>
</Grid>
</Grid>
我的结果:
为了验证我的实现,我创建了一个像这样的视图。这TextBlock.Text
绑定到集合中的第一项。这ItemsControl
与集合本身绑定。
- 按“添加员工”按钮会添加一个
EmployeeViewModel
集合中的对象以及TextBlock
and ItemsControl
已按预期更新。
- 再次点击“添加员工”,
ItemsControl
已更新为另一个条目。伟大的!
- 按“增加员工年龄”按钮。这
Age
每一项的属性加1。PropertyChanged
事件被引发。这ItemPropertyChanged
事件处理程序被调用。这Textblock
已按预期更新。但是,那ItemsControl
没有更新。
我的印象是ItemsControl
当Employee.Age
根据中的答案进行更改当 Item 更改时通知 ObservableCollection https://stackoverflow.com/questions/8490533/notify-observablecollection-when-item-changes.