A custom dependency properties in WPF applications is usually looks like:
class MyControl : Control { public Brush ForeGround { get { return (Brush)this.GetValue(ForeGroundProperty); } set { this.SetValue(ForeGroundProperty, value); } } public static readonly DependencyProperty ForeGroundProperty = DependencyProperty.Register( "ForeGround", typeof(Brush), typeof(MyControl)); }
There are a number of problems with that:
this.GetValue() requires a cast.DependencyProperty.Register may be different from the property’s name.Making the calls to GetValue() and SetValue() type safe by redirecting them through a generic typed Property<> instance may reduce the complexity a bit.
Additionally, the property name can be derived from a lambda expression to support consistent refactoring scenarios:
public Brush ForeGround { get { return ForeGroundProperty[this]; } set { ForeGroundProperty[this] = value); } } public static Property<Brush> ForeGroundProperty = new Property<MyControl, Brush>(c => c.Foreground);
That just looks a lot cleaner and fixes the problems above.
The code behind that is:
public struct Property<ValueT> { Property(DependencyProperty prop) { _depProp = prop; } readonly DependencyProperty _depProp; public static implicit operator Property<ValueT>(PropertyBase prop) { return new Property<ValueT>(prop.DependencyProperty); } public static implicit operator DependencyProperty(Property<ValueT> prop) { return prop._depProp; } public ValueT this[DependencyObject obj] { get { return (ValueT)obj.GetValue(_depProp); } set { obj.SetValue(_depProp, value); } } } public abstract class PropertyBase { public readonly DependencyProperty DependencyProperty; protected PropertyBase(DependencyProperty prop) { DependencyProperty = prop; } } public sealed class Property<ContainerT, ValueT> : PropertyBase { public Property(Expression<Func<ContainerT, ValueT>> accessor) : base(DependencyProperty.Register(nameOfMember(accessor), typeof(ValueT), typeof(ContainerT))) { } static string nameOfMember(Expression<Func<ContainerT, ValueT>> expression) { var memberexp = expression.Body as MemberExpression; if (memberexp == null) throw new ArgumentException("Failed to get name of expression member", "expression"); return memberexp.Member.Name; } }
Two comments:
Property<> can implicitly used as DependencyProperty, just in case it needs to be passed to another method.Property<> is a struct, just holding a reference to the registered DependencyProperty instance. The one additional temporary object is forgotten by the GC.