2009-02-28 54 views
4

定義WPF性能過長:尋找DependencyProperty.Register快捷

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)); 
    } 
} 

有更好的幫手嗎?

回答

6

這是一些代碼。此代碼是邪惡的,但我想說明如何做到這一點,而無需使用塞西爾,或不必創建一個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); 
    } 
} 
+0

一件事在你的榜樣錯過的是富屬性包裝聲明,找出類型所需。但這太棒了! :-) – alex2k8 2009-03-01 13:26:48

4

我同意依賴屬性如此之久是一種痛苦。我不使用助手,但Visual Studio有一個很棒的內置代碼片段,可以通過鍵入wpfdp來使用它。

這就是我快速填充一堆依賴屬性的方法。

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; 
     } 

我有隻顯示wher e有可能宣佈成員 我也設置了$ SelfType $擴展到父類型,這裏是類名稱

5

這是我的嘗試。它比Alun Harford的IL閱讀方法更安全。

此助手具有以下特點:

  • 爲依賴屬性支持和附加屬性
  • 在一個類型安全的方式提供了屬性名稱,W/O(魔術)字符串(使用表達式樹)
  • 類型安全的回調支持,與一般的參數

首先,我會告訴用法:

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; } } 
}