使用DataTemplate和ItemTemplate的数据错误26 [英] Data Error 26 with DataTemplate and ItemTemplate

查看:89
本文介绍了使用DataTemplate和ItemTemplate的数据错误26的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a TabControl with a single specific tab and a collection bound to a collection of VMs, using a different user control. To do this I use a CompositeCollection and DataTemplates defined in the control's resources, selecting correct user control based on the VM type (acting as ContentTemplate).

我还设置了一个ItemTemplate用绑定来定义选项卡项目的名称,但是我没有在资源中定义它,因为我想会与 ContentTemplate的名称冲突。

I also set an ItemTemplate to define the tab item's name with binding, but it's not defined in the resource as I guess would conflict with the "ContentTemplate" ones.

它可以正常工作,但是我看到了跟踪以下错误:

It works fine, but I see the following error traced:


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

System.Windows.Data Error: 26 : ItemTemplate and ItemTemplateSelector are ignored for items already of the ItemsControl's container type; Type='TabItem'

ContentTemplate和ItemTemplate之间似乎存在一些冲突,但我不知道如何解决?

It looks like there's some conflict between ContentTemplate and ItemTemplate, but I don't know how to fix it?

代码如下:

<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>


推荐答案

您观察到的错误非常明显。

您将 TabControl ItemsSource 定义为 CompositeCollection 包含不同类型的元素:

The error you observe is pretty obvious.
You define the ItemsSource of your TabControl as a CompositeCollection that contains elements of different types:


  • a TabItem 常规 ;

  • 一堆 Person 视图模型。

  • a TabItem "General";
  • a bunch of Person viewmodels.

因此,您只是在一个集合中混合了一个视图和一些视图模型-并非整齐。 WPF会通过错误消息通知您。引擎尝试为商品创建视图(使用 DataTemplate s),突然遇到一个已经指定的视图( TabItem ),它正是项目容器的类型(由于 TabControl 的原因,每个视图模型的视图将插入到 TabItem 容器)。因此WPF只需将 TabItem 插入 TabControl 并通知它未使用任何 ItemTemplate ItemTemplateSelector 来创建它。

So you're just mixing in one collection a view and some viewmodels - that's not neat. WPF informs you about this with the error message. The engine tries to create views (using DataTemplates) for the items and suddenly encounters an already specified view (a TabItem) that is exactly of type of the item container (because for the TabControl, a view for each viewmodel will be inserted in a TabItem container). So WPF simply inserts the TabItem into the TabControl and notifies that it has not used any ItemTemplate or ItemTemplateSelector for creating it.

您可以简单地忽略此错误,因为在

You could simply ignore this error, because in the end the control should look like you want it to (I suppose).

另一种(可能更整洁)的方法是不将视图和视图模型混合在一个集合中,而是为常规标签指定一个常规视图模型:

An alternative (and probably neater) way is not to mix views and viewmodels in one collection, but rather specify a "general" viewmodel for the "General" tab:

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

当然,然后您需要告诉WPF如何可视化它:

And of course you then need to tell WPF how to visualize it:

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






更新



解决您的评论中的问题。


Update

To address the issues in your comments.

1。
如何将GeneralViewModel绑定到DataContext中存在的那个?

这是可能的,但是会产生一些开销。您必须为此创建一个绑定代理。 (在在这里看。)

您需要的第二件事是标记扩展: / p>

1. How do I bind the GeneralViewModel to the one that exist in my DataContext?
This is possible, but with some overhead. You have to create a binding proxy for this. (Take a look here.)
The second thing you will need is a markup extension:

class BindingProxyValue : MarkupExtension
{
    public BindingProxy Proxy { get; set; }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return Proxy.DataContext;
    }   
}

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

Use this markup extension together with the binding proxy in your collection:

<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 中的项目。

You can extend the markup extension as you like, e.g. in such a way that it can observe the object updates and replace the item in the target CompositeCollection.

2。
如何指定常规选项卡的标题名称?

您可以使用 ItemTemplate s,但是它变成了有点复杂。您必须为 TabControl 实现 DataTemplateSelector

2. How do I specify general tab's header name?
You can use ItemTemplates, but it becomes a little bit complicated. You have to implement a DataTemplateSelector for your TabControl:

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 用于不同的 TabItem s:

Then you can define the different ItemTemplates for different TabItems:

<TabControl.Resources>
    <!-- ... -->
    <DataTemplate x:Key="GeneralTabItemTemplate">
        <TextBlock Text="General" />
    </DataTemplate>
    <DataTemplate x:Key="PersonTabItemTemplate">
        <TextBlock Text="{Binding FirstName}" />
    </DataTemplate>
</TabControl.Resources>

问题是:这种努力值得吗?还是可以接受该错误消息26 ?您决定。

这篇关于使用DataTemplate和ItemTemplate的数据错误26的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆