从视图中绑定到ViewModel中的复杂对象?
说,例如我有以下类型:从视图中绑定到ViewModel中的复杂对象?
public class Site
{
public string Name { get; set; }
public int SiteId { get; set; }
public bool IsLocal { get; set; }
}
上述类型可以被分配在一个欢迎使用属性被保持在一个ViewModel像这样假设的对应支持字段已创建,但这里省略OFC:
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}" />
可以通过使用点符号语法扩展绑定?例如:
<TextBlock x:Name="StatusMessageTextBlock"
Width="Auto"
Height="Auto"
Style="{StaticResource StatusMessageboxTextStyle}"
**Text="{Binding SelectedSite.Name,**
Mode=OneWay,
UpdateSourceTrigger=PropertyChanged}" />
似乎是一个有趣的功能,但我的直觉是没有一个我的DC是在运行时被分配所以在设计时或编译时,我看不到任何线索,可以实现此功能,或不?
纠正我,如果误解了一个复杂的对象是什么,我简化了我的这个问题。
当然这是可能的。但是,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);
}
}
}
}
而且你的观点可能会是这个样子(假设SitesViewModel
类型的DataContext
):
<ListBox ItemsSource="{Binding Sites}" SelectedItem="{Binding SelectedSite}"/>
下面是什么对我有效:
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属性的绑定扩展显示我们不绑定到简单的直接属性,而是实际绑定到自定义类型。潜在地消除了创造更多公共财产的需要。
您还将视图与您的域模型绑定在一起。我会建议反对这一点,就像我在答案中所做的那样。几乎不可避免地,您会发现 - 您迟早需要使用您的域数据打包的额外的,特定于查看的信息。如果你有一堆代码直接绑定到域对象,它会使重构工作变得更加困难。尽管视图模型最初并不向域对象添加任何内容,但最好咬住子弹并仅使用视图模型来处理所有事情。 – 2012-04-20 14:12:07
我明白你来自哪里......我将保持我的工作原样,并让这个问题自然而然地出现。我学习的最佳方式就是亲眼目睹问题。 =) – IbrarMumtaz 2012-04-24 08:43:25
嗯......你是说我的简单类型'网站'需要实现'INotifyPropertyChanged'界面? – IbrarMumtaz 2012-04-19 19:29:22
@IbrarMumtaz:如果你有改变的属性(比如'Name'),那么是的。如果类型中的所有属性都是只读的,那么不需要实现'INotifyPropertyChanged',因为没有属性会改变。 – 2012-04-19 19:31:18
我正在使用MVVM Light框架,这使得事情变得更容易,但我不熟悉实现此接口的自定义类型的技术,我一直认为这是您的ViewModels必须执行此操作。有一篇文章解释了这种方法? – IbrarMumtaz 2012-04-19 19:31:30