gpt4 book ai didi

c# - 当更新 ObservableCollection 中的项目时更新 ItemsControl

转载 作者:可可西里 更新时间:2023-11-01 09:07:18 30 4
gpt4 key购买 nike

问题:

  • 您在查看。
  • 您将 ItemsControl.ItemsSource 属性绑定(bind)到 ViewModel 中的 ObservableCollection
  • 当一个项目被添加到 ObservableCollection 或从中删除时,您的 View 会按预期更新。
  • 但是,当您更改 ObservableCollection 中某个项目的属性时, View 不会更新。

背景:

看来这是很多WPF开发者遇到的通病。已经被问过几次了:

Notify ObservableCollection when Item changes

ObservableCollection not noticing when Item in it changes (even with INotifyPropertyChanged)

ObservableCollection and Item PropertyChanged

我的实现:

我尝试在 Notify ObservableCollection when Item changes 中实现公认的解决方案.基本思想是在您的 MainWindowViewModel 中为 ObservableCollection 中的每个项目连接一个 PropertyChanged 处理程序。当一个项目的属性被更改时,事件处理程序将被调用,并且 View 会以某种方式更新。

我无法让实现工作。这是我的实现。

View 模型:

class ViewModelBase : INotifyPropertyChanged 
{
public event PropertyChangedEventHandler PropertyChanged;

protected void RaisePropertyChanged(string propertyName = "")
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}

项目 View 模型:

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);
}
}

主窗口 View 模型:

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");
}
}

查看:

<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>

我的结果:

为了验证我的实现,我创建了一个像这样的 View 。 TextBlock.Text 绑定(bind)到集合中的第一项。 ItemsControl 绑定(bind)到集合本身。

  • 按下“添加员工”按钮会在集合中添加一个 EmployeeViewModel 对象,并且 TextBlockItemsControl 都会按预期更新。
  • 再次按下“添加员工”,ItemsControl 将更新为另一个条目。太棒了!
  • 按下“增加员工年龄”按钮。每个项目的 Age 属性递增 1。引发 PropertyChanged 事件。 ItemPropertyChanged 事件处理程序被调用。 Textblock 按预期更新。但是,ItemsControl 没有更新。

我的印象是,当 Employee.Age 根据 Notify ObservableCollection when Item changes 中的答案更改时,ItemsControl 也应该更新。 .

enter image description here

最佳答案

我使用 Snoop 找到了答案调试 XAML。

问题是您正在尝试绑定(bind)到 ToString() 方法并且不会引发 PropertyChanged 事件。如果您查看 XAML 绑定(bind),您会注意到 ObservableCollection 实际上正在发生变化。

Snoop Showing Correct Binding

现在查看每个项目控件及其在“文本”属性中的文本绑定(bind)。没有,只有文字。

Snoop showing no data binding to elements in the items control

要解决此问题,只需添加一个 ItemsControl ItemTemplate 和一个包含您希望显示的元素的 DataTemplate。

<ItemsControl Grid.Row="1" ItemsSource="{Binding Path=Employees, UpdateSourceTrigger=PropertyChanged}" BorderBrush="Red" BorderThickness="1" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat=" {0} is {1} years old">
<Binding Path="Name"/>
<Binding Path="Age"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

我们现在对绑定(bind)开了绿灯。正在调用 RaisePropertyChanged。

Binding correctly shows green

哒哒!

Solution shown

关于c# - 当更新 ObservableCollection 中的项目时更新 ItemsControl,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28422800/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com