从视图绑定到ViewModel中的复杂对象?

时间:2012-04-19 15:43:10

标签: wpf c#-4.0 data-binding mvvm complextype

比如说我有以下类型:

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

可以将上述类型分配为在ViewModel中的Propety中保存,如果假设已创建相应的后备字段但在此处省略了:

    public Site SelectedSite
    {
        get { return _selectedSite; }
        set
        {
            _selectedSite = value;
            // raise property changed etc
        }
    }

在我的xaml中,直接绑定将是:

            <TextBlock x:Name="StatusMessageTextBlock"
                   Width="Auto"
                   Height="Auto"
                   Style="{StaticResource StatusMessageboxTextStyle}"
                   Text="{Binding MessageToDisplay,
                                  Mode=OneWay,
                                  UpdateSourceTrigger=PropertyChanged}" />

您可以使用点表示法语法扩展绑定吗? e.g:

            <TextBlock x:Name="StatusMessageTextBlock"
                   Width="Auto"
                   Height="Auto"
                   Style="{StaticResource StatusMessageboxTextStyle}"
                   **Text="{Binding SelectedSite.Name,**
                                  Mode=OneWay,
                                  UpdateSourceTrigger=PropertyChanged}" />

看起来像一个有趣的功能,但我的直觉是不行,因为我的DC在RunTime分配,所以在DesignTime或CompileTime,我看不到任何可以使这个功能起作用的线索?

如果我误解了复杂的物体是什么,请纠正我,为了这个问题,我已经简化了我的想法。

2 个答案:

答案 0 :(得分:5)

当然这是可能的。但是,WPF需要知道路径上的任何属性何时发生了变化。为此,您需要实现INotifyPropertyChanged(或其他支持的机制)。在您的示例中,Site和包含SelectedSite的VM都应实现更改通知。)

以下是如何实现您在问题中指定的功能:

// 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);
            }
        }
    }
}

您的观点可能如下所示(假设DataContext类型为SitesViewModel):

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

答案 1 :(得分:0)

以下是对我有用的:

        public Site SelectedSite
        {
            get { return _selectedSite; }
            set
            {
                _selectedSite = value;
                RaisePropertyChanged("SelectedSite");
            }
        }

在我的xaml中,我能够做到:

        <TextBox Name="tbSiteName"
                 Width="250"
                 Height="30"
                 Margin="0"
                 HorizontalAlignment="Left"
                 VerticalAlignment="Top"
                 IsReadOnly="True"
                 Style="{StaticResource MainTextBoxStyle}"
                 Text="{Binding SelectedSite.Name,
                          Mode=OneWay,
                          UpdateSourceTrigger=PropertyChanged}" />

这允许您从站点类型访问数据成员,而无需创建在站点类型上包装每个数据成员的单个属性。然后,各个控件可以绑定到VM中声明的每个属性。以一对一的方式,这种方式可能变得相当冗长。附加到上面显示的TextBox控件的Text属性的绑定扩展显示我们没有绑定到简单的直接属性,但实际上绑定到自定义类型。可能无需创建更多公共属性。