【问题标题】:ItemsControl with multiple DataTemplates具有多个 DataTemplate 的 ItemsControl
【发布时间】:2016-08-01 12:58:46
【问题描述】:

我有一个 ItemsControl,其 Canvas 为 ItemsPanelTemplate 和多个 DataTemplates,如下所示:

    <ItemsControl ItemsSource="{Binding Path=DisplayObjects}">

        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>

        <ItemsControl.Resources>
            <DataTemplate DataType="{x:Type viewModels:Object1ViewModel}">
                <views:Object1UIElement/>
            </DataTemplate>

            <DataTemplate DataType="{x:Type viewModels:Object2ViewModel}">
                <viewModels:Object2UIElement/>
            </DataTemplate>
        </ItemsControl.Resources >

        <ItemsControl.ItemContainerStyle>
            <Style TargetType="ContentPresenter">
                <Setter Property="Canvas.Left" Value="{Binding Path=X"/>
                <Setter Property="Canvas.Top" Value="{Binding Path=Y"/>
                <!-- Serveral more properties that are either attached to the Canvas or UIElement -->
            </Style>
        </ItemsControl.ItemContainerStyle>

    </ItemsControl>

两个视图模型位置 (X,Y) 绑定到 Canvas Left 和 Top 属性。问题是我想以不同的方式将 viewModels 属性绑定到 Canvas。

例如,Object1ViewModel 使用 MultiBinding 转换器,该转换器根据 ItemControl 的大小等因素返回值,其中Object2ViewModel 应直接绑定到 Canvas Left/Top 属性,如上所示。

我尝试直接在 DataTemplate 中设置绑定,这样我就可以为不同的 DataTemplates 设置不同的绑定样式,但这不起作用。对象将无法找到 Canvas,因为它们是在 ContentPresenter 中创建的。

【问题讨论】:

  • 听起来你需要两个不同的 ItemContainerStyles。您可以将 ItemsControl 的 ItemContainerStyleSelector 属性设置为适当的 StyleSelector。
  • @Clemens 谢谢,我通过您的评论解决了这个问题并发布了我的实现。

标签: c# wpf xaml itemscontrol


【解决方案1】:

所以我通过 Clemens 的评论想通了。正如他所说,我需要一个 ItemContainerStyleSelector,所以我创建了一个可以给我适当样式的类:

public class MyItemContainerStyleSelector : StyleSelector
{
    public override Style SelectStyle(object item, DependencyObject container)
    {
        var element = container as FrameworkElement; // this will be a ContentPresenter
        if (element == null) return null;
        var viewModel = element.DataContext;
        if (viewModel is Object1ViewModel)
        {
            return element.FindResource("Object1Style") as Style;
        }
        if (viewModel is Object2ViewModel)
        {
            return element.FindResource("Object2Style") as Style;
        }
        return null;
    }
}

在 xaml 中,我将定义资源中的样式并将 ItemContainerStyleSelector 设置为我的新样式选择器:

<UserControl.Resources>
    <utilities:MyItemContainerStyleSelector x:Key="MyStyleSelector"/>

    <Style x:Key="Object1Style" TargetType="ContentPresenter">
        ...
    </Style>

    <Style x:Key="Object2Style" TargetType="ContentPresenter">
        ...
    </Style>
</UserControl.Resources>

<ItemsControl
    ...
    ItemContainerStyleSelector="{StaticResource MyStyleSelector}" >
</ItemsControl>

执行此操作时,不得设置属性ItemContainerStyle,否则样式选择器将被忽略。

【讨论】:

    【解决方案2】:

    听起来你需要DataTemplateSelector

    public class MyWonderfulTemplateSelector : DataTemplateSelector
    {
        public override DataTemplate
            SelectTemplate(object item, DependencyObject container)
        {
            FrameworkElement element = container as FrameworkElement;
    
            if (element != Object1ViewModel)
            {
                return element.FindResource("DataTemplate1") as DataTemplate;
            } else if (element != Object2ViewModel) {
                return element.FindResource("DataTemplate2") as DataTemplate;
            }
    
            return null;
        }
    }
    

    或者类似的东西。

    【讨论】:

      猜你喜欢
      • 2011-07-25
      • 2017-10-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多