Sunday, February 7, 2010

C# Property class Part 2

Commenter tonyt (from CodeProject) rightly points out that there are drawbacks to this approach: A C# Property Class.
Why:

Because there is a mountain of core functionalty in .NET that relies heavily on things like property access via reflection (like data binding) and via System.ComponentModel (e.g., TypeDescriptor), none of which support your take on implementing properties.

You can implement INotifyPropertyChanged on any class that offers a more efficient way to get notified about property changes, as it requires only one delegate for each listener, regardless of how many supported properties you have.

He's right. But I still want to explore this approach. What if we take the Property class and have it implement INotifyPropertyChanged?
public class Property<T> : INotifyPropertyChanged
{
    protected T _value = default(T);

    public Property()
    {
    }

    public Property(T value)
    {
        _value = value;
    }

    public event EventHandler Changed;

    public event PropertyChangedEventHandler PropertyChanged;

    public virtual T Value
    {
        get { return _value; }
        set
        {
            if ((value != null && !value.Equals(_value)) ||
                (_value != null && !_value.Equals(value)))
            {
                _value = value;
                OnChanged();                    
            }
        }
    }

    public override string ToString()
    {
        return object.ReferenceEquals(_value, null) ? string.Empty : _value.ToString();
    }

    protected virtual void OnChanged()
    {
        if (Changed != null)
            Changed(this, EventArgs.Empty);

        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs("Value"));
    }

    public static implicit operator T(Property property)
    {
        if (property == null)
            return default(T);

        return property.Value;
    }
}

Now we can create an class like so:
class ViewModel
{
    public ViewModel()
    {
        Status = new Property<string>("");
    }

    public Property<string> Status { get; private set; }
}
Note the switch from a readonly field to a read-only property. WPF binding requires properties and does not work with fields.

And then we can bind to that in XAML like so:
<TextBox Text="{Binding Path=Status.Value}"/>
(assuming that the DataContext of the TextBox is a ViewModel like the one above.)

That should go a little way to addressing tonyt's point (mostly because WPF data binding is so robust).

No comments:

Post a Comment