我有一个带有单个特定选项卡的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>
答案 0 :(得分:2)
您观察到的错误非常明显
您将ItemsSource
的{{1}}定义为包含不同类型元素的TabControl
:
CompositeCollection
“General”; TabItem
视图模型。所以你只是在一个集合中混合一个视图和一些视图模型 - 这不是很整洁。 WPF通过错误消息通知您。引擎尝试为项创建视图(使用Person
s)并突然遇到一个已经指定的视图(DataTemplate
),它与项容器的类型完全相同(因为{{1} },每个viewmodel的视图将插入TabItem
容器中)。因此,WPF只需将TabControl
插入TabItem
,并通知它没有使用任何TabItem
或TabControl
来创建它。
你可以简单地忽略这个错误,因为最后控件应该看起来像你想要的那样(我想)。
替代(可能更整洁)的方法不是在一个集合中混合视图和视图模型,而是为“常规”选项卡指定“常规”视图模型:
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没问题吗?你决定了。