WTF WPF TabControl? - PullRequest
       10

WTF WPF TabControl?

3 голосов
/ 20 сентября 2010

Я считаю, что это ошибка в 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. Фактически, я могу заменить заголовок TextBlock любым XAML и получить это сообщение. Я затрудняюсь объяснить это. Есть идеи, или это просто ошибка?

Проблема появляется в конструкторе 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 Ответ

5 голосов
/ 20 сентября 2010

По сути, вы назначаете один и тот же экземпляр TextBlock каждому TabItem.На первой итерации 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>
...