支持附加到依赖属性的类






4.67/5 (9投票s)
提供一种连接到外部 DependencyProperty 的方法
引言
有时,当观察者不是DependencyProperty
的所有者,并且所有者没有设置任何通知方式时,能够观察到DependencyProperty
的更改会很方便。 Microsoft 已经设置了一种使用static
方法DependencyProperty.RegisterAttached
附加到DependencyProperty
的方式,但是,最好将该方法封装在一个类中。
背景
通常,不需要从外部类附加到DependencyProperty
更改事件。 如果需要,通常可以通过提供可以订阅的事件来实现观察者模式。 但是,可能需要观察一个类中的属性,而该类无法或不应进行修改以提供此类事件。 依赖属性的优点之一是,可以观察DependencyProperty
,而无需自定义包含需要观察的DependencyProperty
的类。 我遇到了一个案例,当时我正在创建一个行为来识别悬停状态,并且需要知道控件中包含的按钮何时处于按下状态。 使用DependencyProperty
的RegisterAttached
方法附加到DependencyProperty
非常容易。 但是,由于行为的短暂性,我需要包含清除依赖属性的功能,以防止潜在的内存泄漏。 为了能够清除DependencyProperty
,必须维护指向由DependencyProperty.RegisterAttached
方法创建的DependencyProperty
的指针,即使执行DependencyProperty.RegisterAttached
方法的唯一目的是将PropertyChangedCallback
附加到现有的DependencyProperty
。 但是,要清除DependencyProperty
(FrameworkElement.ClearValue(DependencyProperty)
),您必须具有对DependencyProperty
的引用。 如果该类被static
字段引用,则应清除该值以确保没有内存泄漏。
以下是一个使用类的本地实例创建绑定的类。 如果包含想要绑定的DependencyProperty
的控件存在差异,这是最佳选择。 其中包含Dispose
方法,以确保在取消引用AttachedDependencyProperty
时不会发生内存泄漏。
public class AttachedDependencyProperty<T> : IDisposable
{
DependencyProperty _dependencyProperty;
FrameworkElement _element;
public AttachedDependencyProperty(string propertyName, FrameworkElement element,
PropertyChangedCallback callback)
{
_element = element;
//Bind to a dependency property
_dependencyProperty = DependencyProperty.RegisterAttached("Attached" + propertyName,
typeof(T), typeof(object), new PropertyMetadata(callback));
element.SetBinding(_dependencyProperty, new Binding(propertyName)
{ Source = element });
}
public void Dispose()
{
_element.ClearValue(_dependencyProperty);
}
}
如果类的所有实例都绑定到同一属性,则可以使用以下类。 注意不要从使用实例中将此用于两个不同的控件,因为在此实现中没有办法区分两个不同的属性。
public class AttachedDependencyPropertyStatic<T>
{
DependencyProperty _dependencyProperty;
string _propertyName;
public AttachedDependencyPropertyStatic
(string propertyName, PropertyChangedCallback callback)
{
_propertyName = propertyName;
//Bind to a dependency property
_dependencyProperty = DependencyProperty.RegisterAttached("Attached" + propertyName,
typeof(T), typeof(object), new PropertyMetadata(callback));
}
public void Add (FrameworkElement element)
{
Binding b = new Binding(_propertyName) { Source = element };
element.SetBinding(_dependencyProperty, b);
}
public void Dispose(FrameworkElement element)
{
element.ClearValue(_dependencyProperty);
}
}
请注意,在这两种情况下,我都使用typeof(object)
而不是使用特定的类型。 typeof(object)
可以正常工作,这意味着类需要传递的信息更少。
Using the Code
我创建了一个非常简单的应用程序来演示如何使用两个DependencyProperty
类。 在主页中,我附加到按钮的“IsPressed
”属性,然后仅显示上次按下或释放按钮的日期/时间。 这是一个人为设计的示例,因为捕获按钮向上(MouseLeftButtonUp
)和向下(MouseLeftButtonDown
)事件非常容易。 当我最初创建此代码时,它是用于一个容器,我必须扫描内容以查找按钮并连接到IsPressed DependencyProperty
,以便我可以在按下任何按钮时更改行为。
使用这两个类中的任何一个都非常容易。 以下显示了如何使用实例版本
private AttachedDependencyProperty<bool> property1;
public MainPage()
{
InitializeComponent();
property1 = new AttachedDependencyProperty<bool>
("IsPressed", TestButton1, IsPressedChangedCallback);
}
private void IsPressedChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
…
}
这是一个如何实现静态版本的示例
private static AttachedDependencyPropertyStatic<bool> property2 =
new AttachedDependencyPropertyStatic<bool>
("IsPressed", IsPressedChangedCallbackStatic);
public MainPage()
{
InitializeComponent();
property2.Add(TestButton2);
}
private static void IsPressedChangedCallbackStatic(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
…
}
关注点
如果您查看DependencyProperty
代码,您会看到我在注册DependencyProperty
时并不担心所有者的类型。 我使用对象类型。 这似乎没有任何问题,我不确定为什么 Microsoft 要求所有者类型。
确保在附加到DependencyProperty
时使用正确的类型。 如果使用了错误的类型,那么似乎不会捕获任何事件,并且没有迹象表明为什么会发生这种情况。
历史
- 2011 年 6 月 15 日:初始版本