WTF WPF TabControl?

时间:2010-09-20 06:03:33

标签: wpf xaml wpf-controls xamlparseexception

我认为这是WPF中的一个错误(v4.0,如果重要的话),但是已经很晚了,也许我错过了一些东西。

为了说明的目的,我绑定了一个假的例子:

    <x:Array x:Key="SampleItems" Type="sys:String">
        <sys:String>Foo</sys:String>
        <sys:String>Bar</sys:String>
        <sys:String>Baz</sys:String>
    </x:Array>

这适用于并显示三个具有相同标题和内容的标签:

<TabControl ItemsSource="{StaticResource SampleItems}">
            <TabControl.ItemContainerStyle>
                <Style TargetType="TabItem">
                    <Setter Property="Header" Value="{Binding}" />
                    <Setter Property="Content" Value="{Binding}" />
                </Style>
            </TabControl.ItemContainerStyle>
        </TabControl>

但是,这会引发异常,并显示消息“错误10指定的元素已经是另一个元素的逻辑子元素。首先断开它。”:

<TabControl ItemsSource="{StaticResource SampleItems}">
    <TabControl.ItemContainerStyle>
        <Style TargetType="TabItem">
            <Setter Property="Header">
                <Setter.Value>
                    <!-- Anything here causes this problem. -->
                    <TextBlock Text="{Binding}"/>
                </Setter.Value>
            </Setter>
            <Setter Property="Content" Value="{Binding}" />
        </Style>
    </TabControl.ItemContainerStyle>
</TabControl>

重要的是要注意,这可以与TextBlock中的任何文本重现。实际上,我可以用任何XAML替换标题TextBlock并获取此消息。我无法解释这一点。任何想法,或者这只是一个错误?

问题出现在VS设计器中,但这里也是运行时相关堆栈跟踪的一部分:

   at System.Windows.FrameworkElement.ChangeLogicalParent(DependencyObject newParent)
   at System.Windows.FrameworkElement.AddLogicalChild(Object child)
   at System.Windows.Controls.HeaderedContentControl.OnHeaderChanged(Object oldHeader, Object newHeader)
   at System.Windows.Controls.HeaderedContentControl.OnHeaderChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
   at System.Windows.DependencyObject.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
   at System.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
   at System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs args)
   at System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType)
   at System.Windows.StyleHelper.ApplyStyleOrTemplateValue(FrameworkObject fo, DependencyProperty dp)
   at System.Windows.StyleHelper.InvalidateContainerDependents(DependencyObject container, FrugalStructList`1& exclusionContainerDependents, FrugalStructList`1& oldContainerDependents, FrugalStructList`1& newContainerDependents)
   at System.Windows.StyleHelper.DoStyleInvalidations(FrameworkElement fe, FrameworkContentElement fce, Style oldStyle, Style newStyle)
   at System.Windows.StyleHelper.UpdateStyleCache(FrameworkElement fe, FrameworkContentElement fce, Style oldStyle, Style newStyle, Style& styleCache)
   at System.Windows.FrameworkElement.OnStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
   at System.Windows.DependencyObject.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
   at System.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
   at System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs args)
   at System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType)
   at System.Windows.DependencyObject.SetValueCommon(DependencyProperty dp, Object value, PropertyMetadata metadata, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType, Boolean isInternal)
   at System.Windows.DependencyObject.SetValue(DependencyProperty dp, Object value)
   at System.Windows.Controls.ItemsControl.ApplyItemContainerStyle(DependencyObject container, Object item)
   at System.Windows.Controls.ItemsControl.MS.Internal.Controls.IGeneratorHost.PrepareItemContainer(DependencyObject container, Object item)
   at System.Windows.Controls.ItemContainerGenerator.System.Windows.Controls.Primitives.IItemContainerGenerator.PrepareItemContainer(DependencyObject container)
   at System.Windows.Controls.Panel.GenerateChildren()

1 个答案:

答案 0 :(得分:5)

基本上你正在做的是为每个TabItem分配一个TextBlock的相同实例。在第一次迭代中,TextBlock被添加到第一个TabItem。在第二次迭代中,非常相同的 TextBlock被添加到可视树中。你看到的错误信息是试图告诉你TextBlock不能有两个父母(那里有一个笑话)。

可以为这些设置模板。模板指示TabItem为每个创建的项目创建一组新的视觉效果。

<TabControl ItemsSource="{StaticResource SampleItems}">
    <TabControl.ItemContainerStyle>
        <Style TargetType="TabItem">
            <Setter Property="HeaderTemplate">
                <Setter.Value>
                    <DataTemplate>
                         <TextBlock Text="{Binding}"/>
                    </DataTemplate>
                </Setter.Value>
            </Setter>
            <Setter Property="Content" Value="{Binding}" />
        </Style>
    </TabControl.ItemContainerStyle>
</TabControl>