DataTemplate和ItemTemplate的数据错误26

时间:2017-06-09 12:29:08

标签: wpf xaml datatemplate

我有一个带有单个特定选项卡的TabControl,以及使用不同用户控件绑定到一组VM的集合。为此,我使用控件资源中定义的CompositeCollection和DataTemplates,根据VM类型选择正确的用户控件(充当ContentTemplate)。

我还设置了一个ItemTemplate来定义带有绑定的标签项名称,但是它没有在资源中定义,因为我猜想会与“ContentTemplate”冲突。

它工作正常,但我看到跟踪错误:

  

System.Windows.Data错误:26:对于ItemsControl容器类型的项目,将忽略ItemTemplate和ItemTemplateSelector;类型= '的TabItem'

看起来ContentTemplate和ItemTemplate之间存在一些冲突,但我不知道如何修复它?

代码如下:

<TabControl HorizontalAlignment="Left" Height="300" Width="500">
    <TabControl.Resources>
        <CollectionViewSource x:Key="personCollection" Source="{Binding Persons}" />
        <DataTemplate DataType="{x:Type viewModel:Main}">
            <local:MainView />
        </DataTemplate>
        <DataTemplate DataType="{x:Type viewModel:Person}">
            <local:PersonView />
        </DataTemplate>
    </TabControl.Resources>
    <TabControl.ItemsSource>
        <CompositeCollection>
            <TabItem Header="General" Content="{Binding }"/>
            <CollectionContainer Collection="{Binding Source={StaticResource personCollection}}" />
        </CompositeCollection>
    </TabControl.ItemsSource>
    <TabControl.ItemTemplate>
        <DataTemplate DataType="viewModel:Person">
            <TextBlock Text="{Binding FirstName}" />
        </DataTemplate>
    </TabControl.ItemTemplate>
</TabControl>

1 个答案:

答案 0 :(得分:2)

您观察到的错误非常明显 您将ItemsSource的{​​{1}}定义为包含不同类型元素的TabControl

  • a CompositeCollection“General”;
  • 一堆TabItem视图模型。

所以你只是在一个集合中混合一个视图和一些视图模型 - 这不是很整洁。 WPF通过错误消息通知您。引擎尝试为项创建视图(使用Person s)并突然遇到一个已经指定的视图(DataTemplate),它与项容器的类型完全相同(因为{{1} },每个viewmodel的视图将插入TabItem容器中)。因此,WPF只需将TabControl插入TabItem,并通知它没有使用任何TabItemTabControl来创建它。

你可以简单地忽略这个错误,因为最后控件应该看起来像你想要的那样(我想)。

替代(可能更整洁)的方法不是在一个集合中混合视图和视图模型,而是为“常规”选项卡指定“常规”视图模型:

ItemTemplate

当然,你需要告诉WPF如何将其可视化:

ItemTemplateSelector

更新

解决评论中的问题。

1。 如何将GeneralViewModel绑定到DataContext中存在的那个?
这是可能的,但有一些开销。您必须为此创建绑定代理。 (看看here。)
您需要的第二件事是标记扩展:

<TabControl.ItemsSource>
    <CompositeCollection>
        <viewModel:GeneralViewModel/>
        <CollectionContainer Collection="{Binding Source={StaticResource personCollection}}" />
    </CompositeCollection>
</TabControl.ItemsSource>

将此标记扩展名与您的集合中的绑定代理一起使用:

<TabControl.Resources>
    <DataTemplate DataType="{x:Type viewModel:GeneralViewModel}">
        <local:GeneralView />
    </DataTemplate>
    <!-- ... -->
</TabControl.Resources>

您可以根据需要扩展标记扩展名,例如以这种方式,它可以观察对象更新并替换目标class BindingProxyValue : MarkupExtension { public BindingProxy Proxy { get; set; } public override object ProvideValue(IServiceProvider serviceProvider) { return Proxy.DataContext; } } 中的项目。

2。 如何指定常规标签的标题名称?
您可以使用<TabControl.Resources> <local:BindingProxy x:Key="Proxy" DataContext="{Binding GeneralViewModel}"/> </TabControl.Resources> <!--...--> <CompositeCollection> <local:BindingProxyValue Proxy="{StaticResource Proxy}"/> <CollectionContainer Collection="{Binding Source={StaticResource personCollection}}" /> </CompositeCollection> ,但它会变得有点复杂。您必须为CompositeCollection

实施ItemTemplate
DataTemplateSelector

然后,您可以为不同的TabControl s定义不同的class YourTabItemDataTemplateSelector : DataTemplateSelector { public override DataTemplate SelectTemplate(object item, DependencyObject container) { FrameworkElement element = container as FrameworkElement; if (element != null && item != null) { if (item is GeneralViewmodel) { return (DataTemplate)element.FindResource("GeneralTabItemTemplate"); } else { return (DataTemplate)element.FindResource("PersonTabItemTemplate"); } } return null; } }

ItemTemplate

问题是:这项工作值得吗?或者您对该错误消息26没问题吗?你决定了。