views:

82

answers:

2

For the sake of argument, here's a simple person class

public class Person : DependencyObject, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public static readonly DependencyProperty FirstNameProperty =
        DependencyProperty.Register( "FirstName",
                                     typeof ( string ),
                                     typeof ( Person ),
                                     null );
    public static readonly DependencyProperty LastNameProperty =
        DependencyProperty.Register( "LastName",
                                     typeof( string ),
                                     typeof( Person ),
                                     null );

    public string FirstName
    {
        get
        {
            return ( string ) GetValue( FirstNameProperty );
        }
        set
        {
            SetValue( FirstNameProperty, value );
            if(PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs( "FirstName" ));
        }
    }

    public string LastName
    {
        get
        {
            return ( string ) GetValue( LastNameProperty );
        }
        set
        {
            SetValue( LastNameProperty, value );
            if ( PropertyChanged != null )
                PropertyChanged( this, new PropertyChangedEventArgs( "LastName" ) );
        }
    }
}

I want to go about creating a readonly property like this

public string FullName
    {
        get { return FirstName + " " + LastName; }
    }

How does binding work in this scenario? I've tried adding a DependancyProperty and raised the PropertyChanged event for the fullname. Basically I just want to have a property that I can bind to that returns the fullname of a user whenever the first or last name changes. Here's the final class I'm using with the modifications.

public class Person : DependencyObject, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public static readonly DependencyProperty FirstNameProperty =
        DependencyProperty.Register( "FirstName",
                                     typeof ( string ),
                                     typeof ( Person ),
                                     null );
    public static readonly DependencyProperty LastNameProperty =
        DependencyProperty.Register( "LastName",
                                     typeof( string ),
                                     typeof( Person ),
                                     null );
    public static readonly DependencyProperty FullNameProperty =
        DependencyProperty.Register( "FullName",
                                     typeof( string ),
                                     typeof( Person ),
                                     null );

    public string FirstName
    {
        get
        {
            return ( string ) GetValue( FirstNameProperty );
        }
        set
        {
            SetValue( FirstNameProperty, value );
            if ( PropertyChanged != null )
            {
                PropertyChanged( this, new PropertyChangedEventArgs( "FirstName" ) );
                PropertyChanged( this, new PropertyChangedEventArgs( "FullName" ) );
            }
        }
    }

    public string LastName
    {
        get
        {
            return ( string ) GetValue( LastNameProperty );
        }
        set
        {
            SetValue( LastNameProperty, value );
            if ( PropertyChanged != null )
            {
                PropertyChanged( this, new PropertyChangedEventArgs( "LastName" ) );
                PropertyChanged( this, new PropertyChangedEventArgs( "FullName" ) );
            }
        }
    }

    public string FullName
    {
        get { return GetValue( FirstNameProperty ) + " " + GetValue( LastNameProperty ); }
    }
}
+2  A: 

I'm not sure what you are trying to achieve here, but why is your Person class inheriting from DependencyObject and why are FirstName and LastName DependencyProperties? If all you want to do is bind the Person properties to user controls on your view, having the Person class implementing INotifyPropertyChanged is enough to make the data binding work. You will typically bind it to properties of a user control that are dependency properties (eg the Text property of a TextBlock).

Try this for you Person class:

using System.ComponentModel;
public class Person : INotifyPropertyChanged
{
    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    private void RaisePropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    #endregion

    private string _firstName;
    public string FirstName
    {
        get { return _firstName; }
        set
        {
            if (value != _firstName)
            {
                _firstName = value;
                RaisePropertyChanged("FirstName");
                RaisePropertyChanged("FullName");
            }
        }
    }

    private string _lastName;
    public string LastName 
    { 
        get { return _lastName; }
        set 
        {
            if (value != _lastName)
            {
                _lastName = value;
                RaisePropertyChanged("LastName");
                RaisePropertyChanged("FullName");
            }
        }
    }

    public string FullName 
    {
        get { return FirstName + " " + LastName; }
    }
}

And use it like this in your view:

<Grid x:Name="LayoutRoot" Background="White" >
    <TextBlock Text="{Binding FullName}"/>
</Grid>

Then, in your codebehind, you could instantiate it like so:

public partial class MainPage : UserControl
{
    public MainPage()
    {
        InitializeComponent();

        DataContext = new Person { FirstName = "John", LastName = "Doe" };
    }
}

HTH, Phil

Phil
+1, this looks good me.
AnthonyWJones
I'm very new to Binding in Silverlight. Most of the examples I've found all use DependencyProperty's. On top of that I couldn't actually get my binding to work until I started using Dependency Properties. Learning Silverlight binding has been a steady uphill battle for me so far.
Matt
+1  A: 

First of all your implementation of the existing FirstName and LastName properties is flawed. The DependencyObject already has ways to inform bindings of changes to the values and values can be changed by other mechanism than calling the Setter methods.

My first question would be why are FirstName and LastName dependency properties at all? That seems like a strange choice for this type of class. Phil's answer has already provided what I would really expect the correct answer to be.

However in case your code was actually a simplification and that there is in fact a genuine need to create dependency properties here is how it should be done:-

public class Person : DependencyObject, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public static readonly DependencyProperty FirstNameProperty =
        DependencyProperty.Register( "FirstName",
                                     typeof ( string ),
                                     typeof ( Person ),
                                     OnNamePropertyChanged);

    public static readonly DependencyProperty LastNameProperty =
        DependencyProperty.Register( "LastName",
                                     typeof( string ),
                                     typeof( Person ),
                                     OnNamePropertyChanged);

    private static void OnNamePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
      ((Person)d).OnNamePropertyChanged();
    }

    private void OnNamePropertyChanged()
    {
      if (PropertyChanged != null)
        PropertyChanged(this, new PropertyChangedEventArgs("FullName")));
    }

    public string FirstName
    {
      get { return GetValue(FirstNameProperty) as string; }
      set { SetValue(FirstNameProperty, value); }
    }

    public string LastName
    {
      get { return GetValue(LastNameProperty) as string; }
      set { SetValue(LastNameProperty, value); }
    }
    public string FullName
    {
      get { return FirstName + " " + LastName; }
    }
}
AnthonyWJones