如何使ItemsControl根据运行时类型选择不同的模板

时间:2010-06-28 13:47:01

标签: wpf silverlight mvvm itemscontrol

我有一个xaml页面,上面有ItemsControl控件。 ItemsControl绑定到ObservableCollection的Guests。来宾集合可以包含两种不同类型的对象:USGuest和UKGuest,两者都继承自Guest。是否可以为ItemsControl制作两个(或更多)模板,并根据集合中当前项的运行时类型自动选择它们?

2 个答案:

答案 0 :(得分:7)

我没有试过这个,但您是否尝试将ItemsSource设置为Guest对象的ObservableCollection并为这两种类型设置DataTemplate?

<DataTemplate DataType="{x:Type my:USGuestViewModel}">
    <my:USGuestView/>
</DataTemplate>
<DataTemplate DataType="{x:Type my:UKGuestViewModel}">
    <my:UKGuestView/>
</DataTemplate>

编辑:'my'是ViewModel和Views所在的命名空间的声明,所以你应该在xaml的开头添加这样的东西:

<UserControl x:Class="my.namespace.SuperView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:my="clr-namespace:my.namespace">

我已经检查过,你不能在ItemTemplate属性中设置两个DataTemplates。但您可以在UserControl Resources Property中设置它们:

<UserControl.Resources>
    <DataTemplate DataType="{x:Type my:USGuestViewModel}">
        <my:USGuestView/>
    </DataTemplate>
    <DataTemplate DataType="{x:Type my:UKGuestViewModel}">
        <my:UKGuestView/>
    </DataTemplate>
</UserControl.Resources>

答案 1 :(得分:2)

对不起,我不是故意成为派对的人,也不提供解决方案。但这是我在Silverlight中使用MVVM时遇到的最大障碍之一。

我过去做过的一件事就是使用一个UserControl,里面只有一个ContentPresenter作为ItemsTemplate。 (这么多层!)在UserControl中,当DataContext发生变化时,我会选择一个模板来使用UserControl的资源。 (模板实际上不必在UserControl中,但我最喜欢封装。)

<强>的MainPage

<UserControl>

  <UserControl.Resources>
    <DataTemplate x:key="itemTemplate">
      <my:ItemView />
    </DataTemplate>
  </UserControl.Resources>

  <ItemsControl ItemTemplate="{StaticResource itemTemplate}" />
</UserControl>

<强> ItemView.xaml:

<UserControl>
  <UserControl.Resources>
    <DataTemplate x:Key="Template1">
      <!-- Template #1 -->
    </DataTemplate>
    <DataTemplate x:Key="Template2">
      <!-- Template #2 -->
    </DataTemplate>
  </UserControl.Resources>

  <ContentPresenter Name="presenter"
                    Content="{Binding}" />

</UserControl>

<强> ItemView.xaml.cs

...
OnDataContextChanged(...)
{
  var content = this.DataContext as MyDataType;
  DataTemplate template;
  switch (content.State) 
  {
    case State1:
      template = this.Resources["template1"] as DataTemplate;
      break;
    case State2:
      template = this.Resources["template2"] as DataTemplate;
      break;
  }
  this.presenter.ContentTemplate = template;
}
...

如果您仍在继续,请注意Silverlight也不提供像WPF中那样的OnDataContextChanged方法。因此,要了解这一点,请参阅Jeremy Likness在此处所说的内容:

http://www.codeproject.com/Articles/38559/Silverlight-DataContext-Changed-Event.aspx

我经常使用它。谢谢,杰里米!

此外,与WPF在该领域提供的所有功能相比,这也存在一些非常严重的限制。例如,伪造一个ItemContainerStyle选择器确实没有好办法。 (我知道。)