Binding to Complex Objects in the ViewModel from the View?

c#-4.0, complextype, data-binding, mvvm, wpf

Solution

Of course this is possible. However, WPF needs to know when any property along the path has changed. To that end, you need to implement `INotifyPropertyChanged` (or other supported mechanisms). In your example, both `Site` and the VM containing `SelectedSite` should implement change notification).

Here's how you could implement the functionality you specified in your question:

// simple DTO
public class Site
{
   public string Name { get; set; }
   public int SiteId { get; set; }
   public bool IsLocal { get; set; }
}

// base class for view models
public abstract class ViewModel
{
    // see http://kentb.blogspot.co.uk/2009/04/mvvm-infrastructure-viewmodel.html for an example
}

public class SiteViewModel : ViewModel
{
    private readonly Site site;

    public SiteViewModel(Site site)
    {
        this.site = site;
    }

    // this is what your view binds to
    public string Name
    {
        get { return this.site.Name; }
        set
        {
            if (this.site.Name != value)
            {
                this.site.Name = value;
                this.OnPropertyChanged(() => this.Name);
            }
        }
    }

    // other properties
}

public class SitesViewModel : ViewModel
{
    private readonly ICollection<SiteViewModel> sites;
    private SiteViewModel selectedSite;

    public SitesViewModel()
    {
        this.sites = ...;
    }

    public ICollection<SiteViewModel> Sites
    {
        get { return this.sites; }
    }

    public SiteViewModel SelectedSite
    {
        get { return this.selectedSite; }
        set
        {
            if (this.selectedSite != value)
            {
                this.selectedSite = value;
                this.OnPropertyChanged(() => this.SelectedSite);
            }
        }
    }
}

And your view might look something like this (assuming a `DataContext` of type `SitesViewModel`):

<ListBox ItemsSource="{Binding Sites}" SelectedItem="{Binding SelectedSite}"/>

Problem

Say for example I have the following type: ``` public class Site { public string Name { get; set; } public int SiteId { get; set; } public bool IsLocal { get; set; } } ``` The above type can be assigned to be held in a Propety in a ViewModel like so assuming a corresponding backing field has been created but omitted here ofc: ``` public Site SelectedSite { get { return _selectedSite; } set { _selectedSite = value; // raise property changed etc } } ``` In my xaml a straight forward binding would be: ``` <TextBlock x:Name="StatusMessageTextBlock" Width="Auto" Height="Auto" Style="{StaticResource StatusMessageboxTextStyle}" Text="{Binding MessageToDisplay, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" /> ``` Can you extend a binding by using the dot notation syntax? e.g: ``` <TextBlock x:Name="StatusMessageTextBlock" Width="Auto" Height="Auto" Style="{StaticResource StatusMessageboxTextStyle}" **Text="{Binding SelectedSite.Name,** Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" /> ``` Seems like a an interesting feature but my gut instinct is a no as my DC is being assigned at RunTime so at DesignTime or CompileTime, I can't see any clues that could make this feature work or not? Correct me if have misunderstood what a complex object is, I have simplified mine down for the sake of this question.

Original source