Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Binding to Complex Objects in the ViewModel from the View?

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.

like image 363
IbrarMumtaz Avatar asked Apr 19 '12 15:04

IbrarMumtaz


1 Answers

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}"/>
like image 200
Kent Boogaart Avatar answered Sep 29 '22 05:09

Kent Boogaart