views:

32

answers:

1

I'm thinking this should be easy, but I can't seem to figure this out.

Take these properties from an example ViewModel (ObservableViewModel implements INotifyPropertyChanged):

class NameViewModel : ObservableViewModel
{ 
    Boolean mShowFullName = false;
    string mFirstName = "Wonko";
    string mLastName = "DeSane";
    private readonly DelegateCommand mToggleName;

    public NameViewModel()
    {
        mToggleName = new DelegateCommand(() => ShowFullName = !mShowFullName);
    }

    public ICommand ToggleNameCommand
    {
        get { return mToggleName; }
    }

    public Boolean ShowFullName
    {
        get { return mShowFullName; }
        set { SetPropertyValue("ShowFullName", ref mShowFullName, value); }
    }

    public string Name
    {
        get { return (mShowFullName ? this.FullName : this.Initials); }
    }

    public string FullName
    {
        get { return mFirstName + " " + mLastName; }
    }

    public string Initials
    {
        get { return mFirstName.Substring(0, 1) + "." + mLastName.Substring(0, 1) + "."; }
    }
}

The guts of such a [insert your adjective here] View using this ViewModel might look like:

<TextBlock x:Name="txtName"
           Grid.Row="0"
           Text="{Binding Name}" />

<Button x:Name="btnToggleName"
        Command="{Binding ToggleNameCommand}"
        Content="Toggle Name"
        Grid.Row="1" />

The problem I am seeing is when the ToggleNameCommand is fired. The ShowFullName property is properly updated by the command, but the Name binding is never updated in the View.

What am I missing? How can I force the binding to update? Do I need to implement the Name properties as DependencyProperties (and therefore derive from DependencyObject)? Seems a little heavyweight to me, and I'm hoping for a simpler solution.

Thanks, wTs

+1  A: 

You need to explicitly notify that Name has changed, otherwise the Binding system has no way to know. You can either call NotifyPropertyChanged for the property "Name" when you set ShowFullName or you can modify the Name property to have a private setter and update it explicitly (calling NotifyPropertyChanged as part of the Name property setter), rather than having the getter evaluate a function.


Note that you'll need to do the same thing for the other two read-only properties. Making them Dependency properties would also work, but I prefer to avoid these unless I'm implementing a control which will be a target for Binding. They're heavy-weight if you only need property change notification.

Dan Bryant
Doh! Of course! +1 for you, -1 for me. :)At least I was right about the DP implementation, and the reason to avoid it.
Wonko the Sane
I've run into this problem before, as it's a common issue when you have multiple properties that are different views of the same underlying data. I tend to follow the get; private set; approach these days and encapsulate the update in a RefreshX method called whenever one of the underlying properties is changed. This is cleaner for me, since I'm using PostSharp to implement INotifyPropertyChanged and this way I don't need to create a new explicit OnPropertyChanged call.
Dan Bryant