我有一个名为MyComponent的类,它有一个DependencyProperty caled BackgroundProperty。
public class MyComponent
{
public MyBackground Background
{
get { return (MyBackground)GetValue(BackgroundProperty); }
set { SetValue(BackgroundProperty, value); }
}
public static readonly DependencyProperty BackgroundProperty =
DependencyProperty.Register("Background", typeof(MyBackground),
typeof(MyComponent), new FrameworkPropertyMetadata(default(MyBackground), new PropertyChangedCallback(OnPropertyChanged)));
}
MyBackground是一个派生自DependencyObject的类,它有一些DependencyProperties。
public class MyBackground : DependencyObject
{
public Color BaseColor
{
set { SetValue(BaseColorProperty, value); }
get { return (Color)GetValue(BaseColorProperty); }
}
public static readonly DependencyProperty BaseColorProperty =
DependencyProperty.Register("BaseColor", typeof(Color),
typeof(MyBackground ), new UIPropertyMetadata(Colors.White));
[...]
}
现在,我想要的是当MyBackground中的属性被更改时,MyComponent将被通知MyBackground已经更改,并且名为OnPropertyChanged的PropertyChangedCallback被调用。
答案 0 :(得分:3)
请耐心等待一秒钟,因为看起来你正试图违背WPF的规定。由于您似乎正在编写与显示逻辑相关的代码,因此使相关DependencyObject
彼此交互的典型方法是通过绑定。
例如,如果MyComponent
是某种控件并且在Background
中使用ControlTemplate
属性,那么您将使用引用TemplateBinding
的{{1}} {1}}属性和任何重要的子属性。
从1)您可能已经知道并且2)您要么没有使用模板,要么没有它们可用,您可以在代码中设置绑定以响应{{1}的更改属性。如果您提供有关Background
方法的详细信息,我可以提供一些示例代码。
答案 1 :(得分:3)
执行所描述的一种方法是从Freezable而不是DependencyObject派生。当Freezable的属性更改任何DO引用的PropertyChangedCallback时,将调用Freezable,以便调用MyComponent的Background属性。在这种情况下,e.OldValue和e.NewValue将是相同的参考。内部WPF在事件args上有一些标志,表明它是一个子对象更改。
这就是框架对画笔这样的东西所做的事情,这样如果改变SolidColorBrush的Color属性,元素就会失效。如果一个对象永远不会被改变(或者你想让它保持线程安全),那么就可以冻结对象(即使它不可变)。
BTW我可能会避免使用Background作为属性的名称。大多数开发人员都会假设它是Brush类型,因为框架在其几个元素(例如控件,边框)上使用该命名属性。
答案 2 :(得分:2)
听起来好像要使用DependencyPropertyDescriptor和AddValueChanged。
以下是一篇文章:http://www.codeproject.com/Articles/34741/Change-Notification-for-Dependency-Properties.aspx
..可能还有更好的实施方式:http://agsmith.wordpress.com/2008/04/07/propertydescriptor-addvaluechanged-alternative/
答案 3 :(得分:0)
这是我为WPF编写的一小类静态扩展方法 - 它允许您为任何DependencyObject上的任何DependencyProperty更改注册EventHandler或Action回调。不需要更改依赖项对象。
它还可以防止递归(即,如果你在回调期间改变了同一个属性,等等。)
它利用了@ScottBilas链接到的DependencyPropertyDescriptor。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows;
namespace BrainSlugs83.Writes.Too.Much.Code
{
public static class WpfExtensions
{
public static void OnPropertyChanged<T>(this T obj, DependencyProperty prop, Action<T> callback) where T : DependencyObject
{
if (callback != null)
{
obj.OnPropertyChanged(prop, new EventHandler((o, e) =>
{
callback((T)o);
}));
}
}
public static void OnPropertyChanged<T>(this T obj, DependencyProperty prop, EventHandler handler) where T : DependencyObject
{
var descriptor = DependencyPropertyDescriptor.FromProperty(prop, typeof(T));
descriptor.AddValueChanged(obj, new EventHandler((o, e) =>
{
if (handler != null)
{
if (o == null) { handler(o, e); }
else
{
lock (PreventRecursions)
{
if (IsRecursing(obj, prop)) { return; }
SetIsRecursing(obj, prop, true);
}
try
{
handler(o, e);
}
finally
{
SetIsRecursing(obj, prop, false);
}
}
}
}));
}
#region OnPropertyChanged Recursion Prevention
private static readonly Dictionary<object, List<DependencyProperty>> PreventRecursions = new Dictionary<object, List<DependencyProperty>>();
private static bool IsRecursing(object obj, DependencyProperty prop)
{
lock (PreventRecursions)
{
List<DependencyProperty> propList = null;
if (PreventRecursions.ContainsKey(obj))
{
propList = PreventRecursions[obj];
}
return propList == null ? false : propList.Contains(prop);
}
}
private static void SetIsRecursing(object obj, DependencyProperty prop, bool value)
{
lock (PreventRecursions)
{
List<DependencyProperty> propList = null;
if (PreventRecursions.ContainsKey(obj))
{
propList = PreventRecursions[obj];
}
if (propList == null)
{
if (!value) { return; }
propList = PreventRecursions[obj] = new List<DependencyProperty>();
}
if (value)
{
if (!propList.Contains(prop))
{
propList.Add(prop);
}
}
else
{
while (propList.Contains(prop))
{
propList.Remove(prop);
}
if (!propList.Any())
{
propList = PreventRecursions[obj] = null;
}
}
}
}
#endregion
public static bool IsInDesignMode(this DependencyObject obj)
{
try
{
return DesignerProperties.GetIsInDesignMode(obj);
}
catch { /* do nothing */ }
return false;
}
}
}