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

发布于 2024-09-07 03:37:51 字数 203 浏览 1 评论 0原文

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

I have a xaml page that has an ItemsControl control on it. ItemsControl is bound to Guests which is ObservableCollection. Guests collection can have objects of two different types: USGuest and UKGuest, both inheriting from Guest. Is it possible to make two (or more) templates for ItemsControl and make it automatically choose between them depending on the run-time type of the current item in collection?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

方圜几里 2024-09-14 03:37:51

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

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

编辑:“my”是 ViewModel 和 View 所在的命名空间的声明,因此您应该在 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 属性中设置两个 DataTemplate。但您可以在 UserControl 资源属性中设置它们:

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

I haven't tried this, but have you tried to set the ItemsSource to a ObservableCollection of Guest objects and the set the DataTemplate for both types?

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

EDIT: 'my' is a declaration of the namespace where your ViewModels and Views live, so you should add something like this in the beggining of the 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">

I've checked and you cannot set two DataTemplates in the ItemTemplate property. But you can set them in your 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>
看海 2024-09-14 03:37:51

抱歉,我无意成为派对扫兴者并且不提供解决方案。但这是我在 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 Selector。 (据我所知。)

Sorry, I didn't mean to be a party pooper and not offer a solution. But this is one of the biggest hurdles I run into when using MVVM in Silverlight.

One thing I've done in the past is use a UserControl with just a ContentPresenter inside as the ItemsTemplate. (So many layers!) In the UserControl, when the DataContext changes, I would chose a template to use from the resources of the UserControl. (The templates would not actually have to be inside the UserControl, but I like that encapsulation the best.)

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;
}
...

And if you're still following along, note that Silverlight also doesn't provide an OnDataContextChanged method like you get in WPF. So, to cover that, see what Jeremy Likness says about it over here:

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

I use that pretty often. Thanks, Jeremy!

Also, there are some pretty severe limitations to this as well, when compared to all of the power that WPF gives you in that arena. For instance, there really is no good way do fake a ItemContainerStyle Selector. (That I know of.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文