NotifyParentObservableCollection(第一部分)监控其子属性的更改






3.50/5 (4投票s)
ObservableCollection 附加到其子项的 PropertyChanged 事件,并相应地引发 ChildPropertyChanged 事件。 当您需要更新/选择/排列/移动项目时非常有用。
目录
引言
GUI编程中最常见的任务包括从列表中选择多个项目,修改多个项目的属性,重新排列列表中的项目,或者将项目从一个列表复制/移动到另一个列表。
我假设您正在使用 WPF 和 MVVM 模式。
让我们考虑以下简单示例。 您想打开/关闭Hex
变量的各个位,像这样
您在 ViewModel 上创建属性,这些属性包含项目列表或集合,并将它们绑定到视图上的一些ItemsControl
。 您创建一个包含CheckBox
的ItemTemplate
,并将它们绑定到项目的属性。 现在怎么办? 您如何实现所需的功能?
您有几种选择
- 为您的项目创建视图模型类,并将所有逻辑放在那里,因此每次
Item.IsSelected
属性更改时,您都会更新Hex
变量。 哎呀,Hex
变量属于父 VM,因此您的项目将必须具有一个成员变量来保存父 VM 或一个委托回调。 - 制作哑项目来保存数据,制作一堆转换器,并在这些转换器/XAML中实现逻辑,像这样;
TextBox.Text = "{Binding CheckBox.IsChecked, Converter=....}"
当然,您需要一个相当复杂的FlagConverter
,它可以组合多个标志值(我的 WPF 库中有很多这样的转换器)。
示例
XAML 本身就非常简单
<ListBox ItemsSource="{Binding Selectors}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsSelected}"
Content="{Binding Caption}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
ViewModel 不可能更简单
private NotifyParentObservableCollection<LookupItem> _selectors;
public NotifyParentObservableCollection<LookupItem> Selectors
{
get { return _selectors; }
private set
{
if (_selectors != null)
{
_selectors.ChildPropertyChanged -= OnSelectorsChildPropertyChanged;
}
_selectors = value;
if (_selectors != null)
{
_selectors.ChildPropertyChanged += OnSelectorsChildPropertyChanged;
}
OnPropertyChanged("Selectors");
}
}
private void OnSelectorsChildPropertyChanged(object sender,
PropertyChangedEventArgs e)
{
var item = sender as LookupItem;
if (e.PropertyName == "IsSelected")
{
if (item.IsSelected)
{
Hex |= (int) item.Value;
}
else
{
Hex &= ~(int) item.Value;
}
}
}
Selectors = new NotifyParentObservableCollection<LookupItem>
{
new LookupItem { Value = 1, Caption = "0x00000001" },
new LookupItem { Value = 2, Caption = "0x00000010" },
new LookupItem { Value = 4, Caption = "0x00000100" },
new LookupItem { Value = 8, Caption = "0x00001000" },
};
瞧,我们完成了任务。 你能超越这种简单性吗?
NotifyParentObsevableCollection 和 LookupItem
public class LookupItem : INotifyPropertyChanged
当您需要更新/选择/排列/移动这些项目时,LookupItem
是一个实用程序类,用作项目的通用 ViewModel。
LookupItem
具有大量对于这些场景最有用的属性,并且它实现了 INotifyPropertyChanged
接口,以便在其任何属性更改时通知其父级 NotifyParentObservableCollection<T>
。 如果您需要更多属性,请继承自它并添加您需要的任何内容。
public class NotifyParentObservableCollection<T> : ObservableCollection<T>
NotifyParentObservableCollection<T>
附加到其子项的 PropertyChanged
事件,并相应地引发 ChildPropertyChanged
事件。
NotifyParentObservableCollection<T>
继承自 ObservableCollection<T>
,并重写 OnCollectionChanged()
和 ClearItems()
以附加/分离子项的处理程序。
就是这样。 再次,你能超越这种简单性吗?
当我编写代码时,我的目标是尽可能多地消除代码行,但不要超过限制。
我的座右铭:代码行越少,潜在错误就越少。
注意
由于 NotifyParentObservableCollection<T>
强烈附加到其子项的 PropertyChanged
事件,因此您必须在使用完后 Clear()
该集合,以消除潜在的内存泄漏。
当然,如果父集合与其子集合具有相同的生命周期,则您可以安全地忽略此建议,但如果子集合可以比集合更长寿,请不要忘记调用 Clear()
。
修订历史
- 2011年1月20日 - 创建了这篇文章。