FreezableCollection 在子属性更改时不提供更改通知
我有一个 FreezableCollection,我想监视其子属性的更改。下面是代码的一小部分:
public class FieldHeading : DependencyObject
{
public static readonly DependencyProperty LayoutProperty = DependencyProperty.Register("Layout", typeof(FieldHeadingLayout), typeof(FieldHeading),
new FrameworkPropertyMetadata(FieldHeadingLayout.Above,
FrameworkPropertyMetadataOptions.AffectsRender |
FrameworkPropertyMetadataOptions.AffectsMeasure |
FrameworkPropertyMetadataOptions.AffectsParentMeasure));
public FieldHeadingLayout Layout
{
get { return (FieldHeadingLayout) GetValue(LayoutProperty); }
set { SetValue(LayoutProperty, value); }
}
}
public class FieldPanel : FrameworkElement
{
private static readonly DependencyProperty FieldHeadingProperty = DependencyProperty.Register("FieldHeading", typeof(FreezableCollection<FieldHeading>), typeof(FieldPanel),
new FrameworkPropertyMetadata(null,
FrameworkPropertyMetadataOptions.AffectsMeasure |
FrameworkPropertyMetadataOptions.AffectsParentMeasure |
FrameworkPropertyMetadataOptions.AffectsRender, HeadingChanged));
private static void HeadingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Debug.WriteLine("Hello");
}
public FreezableCollection<FieldHeading> FieldHeadings
{
get
{ return (FreezableCollection<FieldHeading>) GetValue(FieldHeadingProperty); }
set { SetValue(FieldHeadingProperty, value);}
}
public FieldPanel()
{
AddVisual(_contentVisual = new DrawingVisual());
FieldHeadings = new FreezableCollection<FieldHeading>();
}
}
然后,我们为其中一个 FieldHeadings 的 Layout 分配一个新值,不会生成任何更改通知。显然我错过了一些重要的事情。 HeadingChanged 永远不会被调用。
有关 FreezableCollection 的 MSDN 帮助可在此处找到:FreezableCollection,指出:
事件已更改... 当 Freezable 或其包含的对象被修改时发生。 (继承自 Freezable。)
预先感谢您的帮助。
〜卡梅伦
I have a FreezableCollection for which I want to monitor the changes to sub properties. Here is a subsection of the code:
public class FieldHeading : DependencyObject
{
public static readonly DependencyProperty LayoutProperty = DependencyProperty.Register("Layout", typeof(FieldHeadingLayout), typeof(FieldHeading),
new FrameworkPropertyMetadata(FieldHeadingLayout.Above,
FrameworkPropertyMetadataOptions.AffectsRender |
FrameworkPropertyMetadataOptions.AffectsMeasure |
FrameworkPropertyMetadataOptions.AffectsParentMeasure));
public FieldHeadingLayout Layout
{
get { return (FieldHeadingLayout) GetValue(LayoutProperty); }
set { SetValue(LayoutProperty, value); }
}
}
public class FieldPanel : FrameworkElement
{
private static readonly DependencyProperty FieldHeadingProperty = DependencyProperty.Register("FieldHeading", typeof(FreezableCollection<FieldHeading>), typeof(FieldPanel),
new FrameworkPropertyMetadata(null,
FrameworkPropertyMetadataOptions.AffectsMeasure |
FrameworkPropertyMetadataOptions.AffectsParentMeasure |
FrameworkPropertyMetadataOptions.AffectsRender, HeadingChanged));
private static void HeadingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Debug.WriteLine("Hello");
}
public FreezableCollection<FieldHeading> FieldHeadings
{
get
{ return (FreezableCollection<FieldHeading>) GetValue(FieldHeadingProperty); }
set { SetValue(FieldHeadingProperty, value);}
}
public FieldPanel()
{
AddVisual(_contentVisual = new DrawingVisual());
FieldHeadings = new FreezableCollection<FieldHeading>();
}
}
Then we assign a new value to Layout for one of the FieldHeadings, no change notification is generated. Obviously I'm missing something important. HeadingChanged is never called.
The MSDN help on FreezableCollection, which can be found here: FreezableCollection, states:
Event changed... Occurs when the Freezable or an object it contains is modified. (Inherited from Freezable.)
Thanks in advance for any help.
~ Cameron
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
实际上,您可以做您想做的事情。这正是
FreezableCollection
存在的原因!您需要做的就是将FieldHeading
更改为派生自Freezable
而不是DependencyObject
,并且对集合中的项目的更改将给出与以下相同的更改通知:如果整个项目已被更换。这是一个非常有用但鲜为人知的 WPF 功能。
来自 Charles Petzold 本人,
下面是一个小示例,演示如何使用
FreezableCollection
。我在 Visual Studio 中创建了一个新的 WPF 项目。以下是 MainWindow.xaml.cs 的 XAML 及其背后的 C# 代码:该示例显示一个包含单个
CheckBox
的列表。单击它可切换数据绑定MyFreezableCollection
中项目的IsNice
属性。即使列表中没有添加或删除任何内容,也会调用依赖属性更改回调。Actually, you can do what you're trying to do. This is exactly why
FreezableCollection<T>
exists! All you need to do is changeFieldHeading
to derive fromFreezable
instead ofDependencyObject
and changes to items in the collection will give the same change notification as if the entire item had been replaced.This is an incredibly useful and little-known WPF feature.
From Charles Petzold himself,
Here is a small sample that demonstrates how to use
FreezableCollection<>
. I made a new WPF project in Visual Studio. Here is the XAML for MainWindow.xaml.cs and its C# code behind:The sample displays a list containing a single
CheckBox
. Click on it to toggle theIsNice
property on an item in the data-boundMyFreezableCollection
. Even though nothing is added to or removed from the list, the dependency property change callback is invoked.更改通知处理程序只会在属性值更改时通知您,因此在这种情况下,如果可冻结集合更改为新集合。在属性更改处理程序中,您需要订阅
CollectionChanged
事件,在该事件中,您需要订阅新项目的PropertyChanged
事件。现在,您终于有了一个事件,该事件允许您对属于可冻结集合(即依赖属性)的项的属性更改做出反应。请记住取消订阅旧收藏和旧项目的活动。The change notification handler will only notify you when the value of the property changes, so in this case if the freezable collection changes to a new collection. In your property changed handler you need to subscribe to the
CollectionChanged
event and in that event you need to subscribe to thePropertyChanged
event on the new item. Now, finally, you have an event that will allow you to react to changes in properties of items belonging to a freezable collection that is a dependency property. Remember to unsubscribe to the old collection's and old item's events.问题是,您仅订阅
FieldHeadings
property 更改,这意味着仅当有人分配集合本身的新实例(例如,使用FeildHedings
属性设置器。为了在
Layout
属性更改时接收通知,您必须在FieldHeading
的每个单独实例上订阅它。The thing is that you subscribe only for the
FieldHeadings
property changes, meaning you will receive notifications only if someone assigns a new instance of the collection itself, using, for example, theFeildHedings
property setter.In order to receive notifications when the
Layout
property changes, you have to subscribe to it on each individual instance ofFieldHeading
.