WPF 的选项卡项:指定元素已经是另一个元素的逻辑子元素。先断开连接

发布于 2024-12-08 18:49:55 字数 5408 浏览 0 评论 0原文

我有一个带有 CloseableTabItems 的 CloseableTabControl,我试图动态添加:

public class CloseableTabControl : TabControl
{
    protected override DependencyObject GetContainerForItemOverride()
    {
        return new CloseableTabItem();
    }
}  


public class CloseableTabItem : TabItem
{
    public static readonly RoutedEvent CloseTabEvent =
        EventManager.RegisterRoutedEvent("CloseTab", RoutingStrategy.Bubble,
        typeof(RoutedEventHandler), typeof(CloseableTabItem));

    public event RoutedEventHandler CloseTab
    {
        add { AddHandler(CloseTabEvent, value); }
        remove { RemoveHandler(CloseTabEvent, value); }
    }

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        var closeButton = Template.FindName("closeButton", this) as Button;
        if (closeButton != null)
        closeButton.Click += CloseButtonClick;
    }

    void CloseButtonClick(object sender, RoutedEventArgs e)
    {
        RaiseEvent(new RoutedEventArgs(CloseTabEvent, this));
    }
}

并且 XAML 如下:

    <local:CloseableTabControl Grid.Column="2" Grid.Row="1" SelectedIndex="{Binding SelectedTabIndex}" ItemsSource="{Binding TabItems}">
    <local:CloseableTabControl.Resources>
        <DataTemplate DataType="{x:Type TestEditor:TestEditorViewModel}">
             <TestEditor:TestEditorView/>
        </DataTemplate>
        <DataTemplate DataType="{x:Type TestParameterEditor:TestParameterEditorViewModel}">
             <TestParameterEditor:TestParameterEditorView/>
        </DataTemplate>
    </local:CloseableTabControl.Resources>
    <local:CloseableTabControl.ItemContainerStyle>
        <Style TargetType="local:CloseableTabItem">
            <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type TabItem}">
                    <Grid>
                        <Border Name="Border" Background="{DynamicResource Brush2}" BorderBrush="{DynamicResource Brush5}" BorderThickness="1,1,1,1" CornerRadius="6,6,0,0" >
                            <DockPanel>
                                <ContentPresenter x:Name="ContentSite"
                                     VerticalAlignment="Center"
                                     HorizontalAlignment="Center"
                                     ContentSource="Header"
                                     Margin="12,2,12,2"/>
                                <Button Name="closeButton" 
                                     HorizontalAlignment="Center" 
                                     Margin="3,0,3,0" 
                                     VerticalAlignment="Center" 
                                     Width="16" 
                                     Height="16" 
                                     DockPanel.Dock="Right" 
                                     Style="{DynamicResource CloseableTabItemButtonStyle}" 
                                     ToolTip="Close Tab">
                                     <Path Stretch="Fill" StrokeThickness="0.5" Stroke="#FF333333" Fill="#FF969696" Data="F1 M 2.28484e-007,1.33331L 1.33333,0L 4.00001,2.66669L 6.66667,6.10352e-005L 8,1.33331L 5.33334,4L 8,6.66669L 6.66667,8L 4,5.33331L 1.33333,8L 1.086e-007,6.66669L 2.66667,4L 2.28484e-007,1.33331 Z " HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
                                </Button>
                            </DockPanel>
                         </Border>
                      </Grid>
                      <ControlTemplate.Triggers>
                          <Trigger Property="IsSelected" Value="True">
                              <Setter TargetName="Border" Property="Background" Value="{DynamicResource lightBrush}" />
                          </Trigger>
                          <Trigger Property="IsSelected" Value="False">
                              <Setter TargetName="Border" Property="Background" Value="{DynamicResource Brush1}" />
                          </Trigger>
                      </ControlTemplate.Triggers>
                  </ControlTemplate>
               </Setter.Value>
            </Setter>
            <Setter Property="Header">
                <Setter.Value>
                    <StackPanel Orientation="Horizontal" ToolTip="{Binding Caption}">
                         <Image Height="18" Source="{Binding ImageName}"/>
                         <TextBlock Text="{Binding Title}" Margin="2,0,0,0"/>
                    </StackPanel>
                </Setter.Value>
            </Setter>
         </Style>
      </local:CloseableTabControl.ItemContainerStyle>
  </local:CloseableTabControl>  

当我在此窗口的视图模型的构造函数中仅添加一个选项卡时,一切都很好:

TabItems.Add(TestEditorViewModel);

但是当我添加多个选项卡时,我获取提到的异常。
我尝试按照说明操作 此处 并将 XAML 分离为 ItemTemplateContentTemplate 但这导致了 StackOverFlowException (这是由ContentPresenter 模板的一部分,我不知道为什么)。
有什么想法我应该如何处理这个问题吗?
谢谢

I have a CloseableTabControl with CloseableTabItems I'm trying to add dynamically:

public class CloseableTabControl : TabControl
{
    protected override DependencyObject GetContainerForItemOverride()
    {
        return new CloseableTabItem();
    }
}  


public class CloseableTabItem : TabItem
{
    public static readonly RoutedEvent CloseTabEvent =
        EventManager.RegisterRoutedEvent("CloseTab", RoutingStrategy.Bubble,
        typeof(RoutedEventHandler), typeof(CloseableTabItem));

    public event RoutedEventHandler CloseTab
    {
        add { AddHandler(CloseTabEvent, value); }
        remove { RemoveHandler(CloseTabEvent, value); }
    }

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        var closeButton = Template.FindName("closeButton", this) as Button;
        if (closeButton != null)
        closeButton.Click += CloseButtonClick;
    }

    void CloseButtonClick(object sender, RoutedEventArgs e)
    {
        RaiseEvent(new RoutedEventArgs(CloseTabEvent, this));
    }
}

and the XAML is as follows:

    <local:CloseableTabControl Grid.Column="2" Grid.Row="1" SelectedIndex="{Binding SelectedTabIndex}" ItemsSource="{Binding TabItems}">
    <local:CloseableTabControl.Resources>
        <DataTemplate DataType="{x:Type TestEditor:TestEditorViewModel}">
             <TestEditor:TestEditorView/>
        </DataTemplate>
        <DataTemplate DataType="{x:Type TestParameterEditor:TestParameterEditorViewModel}">
             <TestParameterEditor:TestParameterEditorView/>
        </DataTemplate>
    </local:CloseableTabControl.Resources>
    <local:CloseableTabControl.ItemContainerStyle>
        <Style TargetType="local:CloseableTabItem">
            <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type TabItem}">
                    <Grid>
                        <Border Name="Border" Background="{DynamicResource Brush2}" BorderBrush="{DynamicResource Brush5}" BorderThickness="1,1,1,1" CornerRadius="6,6,0,0" >
                            <DockPanel>
                                <ContentPresenter x:Name="ContentSite"
                                     VerticalAlignment="Center"
                                     HorizontalAlignment="Center"
                                     ContentSource="Header"
                                     Margin="12,2,12,2"/>
                                <Button Name="closeButton" 
                                     HorizontalAlignment="Center" 
                                     Margin="3,0,3,0" 
                                     VerticalAlignment="Center" 
                                     Width="16" 
                                     Height="16" 
                                     DockPanel.Dock="Right" 
                                     Style="{DynamicResource CloseableTabItemButtonStyle}" 
                                     ToolTip="Close Tab">
                                     <Path Stretch="Fill" StrokeThickness="0.5" Stroke="#FF333333" Fill="#FF969696" Data="F1 M 2.28484e-007,1.33331L 1.33333,0L 4.00001,2.66669L 6.66667,6.10352e-005L 8,1.33331L 5.33334,4L 8,6.66669L 6.66667,8L 4,5.33331L 1.33333,8L 1.086e-007,6.66669L 2.66667,4L 2.28484e-007,1.33331 Z " HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
                                </Button>
                            </DockPanel>
                         </Border>
                      </Grid>
                      <ControlTemplate.Triggers>
                          <Trigger Property="IsSelected" Value="True">
                              <Setter TargetName="Border" Property="Background" Value="{DynamicResource lightBrush}" />
                          </Trigger>
                          <Trigger Property="IsSelected" Value="False">
                              <Setter TargetName="Border" Property="Background" Value="{DynamicResource Brush1}" />
                          </Trigger>
                      </ControlTemplate.Triggers>
                  </ControlTemplate>
               </Setter.Value>
            </Setter>
            <Setter Property="Header">
                <Setter.Value>
                    <StackPanel Orientation="Horizontal" ToolTip="{Binding Caption}">
                         <Image Height="18" Source="{Binding ImageName}"/>
                         <TextBlock Text="{Binding Title}" Margin="2,0,0,0"/>
                    </StackPanel>
                </Setter.Value>
            </Setter>
         </Style>
      </local:CloseableTabControl.ItemContainerStyle>
  </local:CloseableTabControl>  

Everything is fine when I'm adding only one tab in this window's viewmodel's constructor:

TabItems.Add(TestEditorViewModel);

but when I'm adding more than one I'm getting the mentioned exception.
I've tried to follow the instructions here and separate the XAML to ItemTemplate and ContentTemplate but this caused a StackOverFlowException (that is caused by the ContentPresenter part of the template, I have no idea why).
Any ideas how should I approach this?
Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

提笔落墨 2024-12-15 18:49:55

问题出在 Header 属性的 Setter 上。当第一个 TabItem 应用了 Style 时,将创建一个新的 StackPanel。当创建第二个 TabItem 并应用 Style 时,相同 StackPanel 将被分配给其 标头 属性。在 WPF 中,视觉对象只能有 1 个父级,因此您会收到上面所述的异常。相反,您应该定义一个包含 StackPanelHeaderTemplate,以便每次将 Style 应用于 TabItemnew StackPanel 是在 WPF 扩充 HeaderTemplate 时生成的。

请参阅此相关帖子:

WTF WPF TabControl?

干杯!

The problem is with your Setter for the Header property. When the first TabItem has the Style applied, a new StackPanel will be created. When the second TabItem is created and has the Style applied the same StackPanel will be assigned to its Header property. In WPF a visual can only have 1 parent, so you receive the stated exception above. Instead you should define a HeaderTemplate which contains the StackPanel so that each time the Style is applied for a TabItem a new StackPanel is generated when WPF inflates the HeaderTemplate.

Please see this related post:

WTF WPF TabControl?

Cheers!

琉璃梦幻 2024-12-15 18:49:55

问题出

<Setter Property="Header">
    <Setter.Value>
        <StackPanel Orientation="Horizontal" ToolTip="{Binding Caption}">
            <Image Height="18" Source="{Binding ImageName}"/>
            <TextBlock Text="{Binding Title}" Margin="2,0,0,0"/>
        </StackPanel>
    </Setter.Value>
</Setter>  

在风格内部。我不确定到底是什么原因造成的,我认为是由于某种原因内容被设置了两次,但解决方案是使用

 <local:CloseableTabControl.ItemTemplate>
     <DataTemplate>
         <StackPanel Orientation="Horizontal" ToolTip="{Binding Caption}">
              <Image Height="18" Source="{Binding ImageName}"/>
              <TextBlock Text="{Binding Title}" Margin="2,0,0,0"/>
         </StackPanel>
     </DataTemplate>
 </local:CloseableTabControl.ItemTemplate>

任何关于问题到底是什么的解释将是最受欢迎的。

The problem was

<Setter Property="Header">
    <Setter.Value>
        <StackPanel Orientation="Horizontal" ToolTip="{Binding Caption}">
            <Image Height="18" Source="{Binding ImageName}"/>
            <TextBlock Text="{Binding Title}" Margin="2,0,0,0"/>
        </StackPanel>
    </Setter.Value>
</Setter>  

inside the style. I'm not sure what causes it exactly, I think it's the content being set twice for some reason, but the solution is to use

 <local:CloseableTabControl.ItemTemplate>
     <DataTemplate>
         <StackPanel Orientation="Horizontal" ToolTip="{Binding Caption}">
              <Image Height="18" Source="{Binding ImageName}"/>
              <TextBlock Text="{Binding Title}" Margin="2,0,0,0"/>
         </StackPanel>
     </DataTemplate>
 </local:CloseableTabControl.ItemTemplate>

Any explanations as to what exactly is the problem will be most welcome.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文