Как заставить ItemsControl выбирать разные шаблоны в зависимости от типа времени выполнения - PullRequest
1 голос
/ 28 июня 2010

У меня есть страница xaml, на которой есть элемент управления ItemsControl.ItemsControl привязан к гостям, который является ObservableCollection.Гостиная коллекция может иметь объекты двух разных типов: USGuest и UKGuest, оба наследуются от Guest.Можно ли создать два (или более) шаблона для ItemsControl и автоматически выбирать между ними в зависимости от типа времени выполнения текущего элемента в коллекции?

Ответы [ 2 ]

7 голосов
/ 28 июня 2010

Я не пробовал этого, но пытались ли вы установить ItemsSource для ObservableCollection объектов Guest и установить DataTemplate для обоих типов?

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

РЕДАКТИРОВАТЬ: 'my' является объявлением пространства имен, в котором живут ваши ViewModels и 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">

Я проверил, и вы не можете установить два DataTemplates в свойстве ItemTemplate. Но вы можете установить их в свойстве ресурсов UserControl:

<UserControl.Resources>
    <DataTemplate DataType="{x:Type my:USGuestViewModel}">
        <my:USGuestView/>
    </DataTemplate>
    <DataTemplate DataType="{x:Type my:UKGuestViewModel}">
        <my:UKGuestView/>
    </DataTemplate>
</UserControl.Resources>
2 голосов
/ 30 июня 2010

Извините, я не хотел быть вечеринкой и не предлагать решения. Но это одно из самых больших препятствий, с которыми я сталкиваюсь при использовании MVVM в Silverlight.

Одна вещь, которую я делал в прошлом, - это использование 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 также не предоставляет метод OnDataContextChanged, как вы получаете в WPF. Итак, чтобы покрыть это, посмотрите, что Джереми Ликнесс говорит об этом здесь:

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

Я использую это довольно часто. Спасибо, Джереми!

Кроме того, есть некоторые довольно серьезные ограничения в этом отношении по сравнению со всей мощью, которую WPF дает вам на этой арене. Например, действительно нет хорошего способа подделать Селектор ItemContainerStyle. (Что я знаю.)

...