寻找DependencyProperty.Register快捷方式

时间:2009-02-28 03:01:36

标签: wpf properties helper

定义WPF属性太长:

public static readonly DependencyProperty FooProperty = 
  DependencyProperty.Register("Foo", typeof(string), typeof(FooClass), new PropertyMetadata("Foooooo"));

我有一个辅助方法,使它缩短一点:

public static readonly DependencyProperty FooProperty =
  WpfUtils.Property<string, FooControl>("Foo", "Foooooo");

代码:

public partial class WpfUtils 
{
    public static DependencyProperty Property<T, TClass>(string name) 
    {
        return Property<T, TClass>(name, default(T));
    }

    public static DependencyProperty Property<T, TClass>(string name, T defaultValue) 
    {
        return DependencyProperty.Register(name, typeof(T), typeof(TClass), new PropertyMetadata(defaultValue));
    }
}

周围有更好的助手吗?

4 个答案:

答案 0 :(得分:6)

这是一些代码。这段代码是邪恶的,但我想展示如何在不使用Cecil的情况下执行此操作,或者必须创建sourceforge项目: - )

要使用它,请致电:

public static readonly DependencyProperty FooProperty = D.P();

代码是:

public class D
{
    [MethodImpl(MethodImplOptions.NoInlining)]
    public static DependencyProperty P()
    {
        StackTrace stackTrace = new StackTrace();
        StackFrame oneUp = stackTrace.GetFrame(1);
        MethodBase callingMethod = oneUp.GetMethod();
        if (!(callingMethod is ConstructorInfo))
        {
            throw new InvalidOperationException("This method must be called from a static constructor/initializer");
        }
        byte[] staticConstructorCode = callingMethod.GetMethodBody().GetILAsByteArray();
        int offsetAfterThisCall = oneUp.GetILOffset() + 5;

        while (staticConstructorCode[offsetAfterThisCall] == OpCodes.Nop.Value)
        {
            offsetAfterThisCall++;
        }

        if (staticConstructorCode[offsetAfterThisCall] != OpCodes.Stsfld.Value)
        {
            throw new InvalidOperationException("Unexpected IL");
        }

        int token = BitConverter.ToInt32(staticConstructorCode, offsetAfterThisCall + 1);

        FieldInfo field = callingMethod.Module.ResolveField(token);

        if (!field.Name.EndsWith("Property") || field.FieldType != typeof(DependencyProperty))
        {
            throw new NotSupportedException("The field the return value of this method will be stored in must be named xxxProperty and be of type DependencyProperty");
        }

        string name = field.Name.Substring(0, field.Name.Length - "Property".Length);
        return DependencyProperty.Register(name, callingMethod.DeclaringType.GetProperty(name).PropertyType, callingMethod.DeclaringType);
    }
}

答案 1 :(得分:5)

这是我的尝试。它比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; } }
}

答案 2 :(得分:4)

我同意依赖属性很长很痛苦。我不使用帮助程序,但Visual Studio有一个很好的内置代码片段,您可以通过键入wpfdp来使用它。

这就是我如何快速填写一堆依赖属性。

答案 3 :(得分:0)

对于那些使用resharper的人,我使用以下模板

//DependencyProperty $PropertyName$
public static readonly DependencyProperty $PropertyName$Property =
      DependencyProperty.Register("$PropertyName$", typeof($PropertyType$), typeof($SelfType$),
      new FrameworkPropertyMetadata($DefaultValue$, $PropertyName$ChangedCallback, $PropertyName$CoerceValue));

public $PropertyType$ $PropertyName${
       set { SetValue($PropertyName$Property, value); }
       get { return ($PropertyType$)GetValue($PropertyName$Property); }
      }

private static void $PropertyName$ChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e){

      $SelfType$ owner = d as $SelfType$;
      if(owner!=null){}

      }

 private static object $PropertyName$CoerceValue(DependencyObject d, object value)   {

            $PropertyType$ val = ($PropertyType$)value;
        return value;
      }

我只在可以申报会员的地方展示 我还设置$ SelfType $扩展为父类型,这里是类名