这是我的尝试。它比 Alun Harford 的 IL 阅读方法更安全。
这个助手有以下特点:
- 支持依赖属性和附加属性
- 以类型安全的方式提供属性名称,不带(魔术)字符串(使用表达式树)
- 类型安全的回调支持,带有通用参数
首先,我将展示用法:
public class Tester : DependencyObject
{
public int Foo
{
get { return (int)GetValue(FooProperty); }
set { SetValue(FooProperty, value); }
}
public static readonly DependencyProperty FooProperty =
For<Tester>.Register(o => o.Foo, 0, onFooChanged);
private static void onFooChanged(Tester obj, DependencyPropertyChangedEventArgs<int> e)
{
}
public string Attached
{
get { return (string)GetValue(AttachedProperty); }
set { SetValue(AttachedProperty, value); }
}
public static readonly DependencyProperty AttachedProperty =
For<Tester>.RegisterAttached(o => o.Attached, "default", onAttachedChanged);
private static void onAttachedChanged(DependencyObject obj, DependencyPropertyChangedEventArgs<string> e)
{
}
}
这是实现:
public static class For<TOwner>
where TOwner : DependencyObject
{
public static DependencyProperty Register<TProperty>(
Expression<Func<TOwner,TProperty>> property,
TProperty defaultValue,
Action<TOwner, DependencyPropertyChangedEventArgs<TProperty>> callback)
{
return DependencyProperty.Register(
getName(property),
typeof(TProperty),
typeof(TOwner),
new FrameworkPropertyMetadata(
defaultValue,
(o, args) => callback((TOwner)o, new DependencyPropertyChangedEventArgs<TProperty>(args))));
}
public static DependencyProperty RegisterAttached<TProperty>(
Expression<Func<TOwner,TProperty>> property,
TProperty defaultValue,
Action<DependencyObject, DependencyPropertyChangedEventArgs<TProperty>> callback)
{
return DependencyProperty.RegisterAttached(
getName(property),
typeof(TProperty),
typeof(TOwner),
new FrameworkPropertyMetadata(
defaultValue,
(o, args) => callback(o, new DependencyPropertyChangedEventArgs<TProperty>(args))));
}
private static string getName<T>(Expression<Func<TOwner,T>> property)
{
var name = ((MemberExpression)property.Body).Member.Name;
return name;
}
}
public struct DependencyPropertyChangedEventArgs<T>
{
public DependencyPropertyChangedEventArgs(DependencyPropertyChangedEventArgs source)
{
m_property = source.Property;
m_oldValue = (T)source.OldValue;
m_newValue = (T)source.NewValue;
}
private readonly DependencyProperty m_property;
public DependencyProperty Property { get { return m_property; } }
private readonly T m_oldValue;
public T OldValue { get { return m_oldValue; } }
private readonly T m_newValue;
public T NewValue { get { return m_newValue; } }
}