【问题标题】:XamlParse Exception when Applying Style应用样式时出现 XamlParse 异常
【发布时间】:2016-08-13 08:56:21
【问题描述】:

这是第一个使用 WPF 和样式的项目。 开发工具为VS2010。

我有以下样式定义:

<!-- Base Style Setting-->
<Style TargetType="{x:Type TabControl}" x:Key="TabControlBase">
    <Setter Property="Height" Value="Auto" />
    <Setter Property="Width"  Value="Auto" />
</Style>

<Style TargetType="{x:Type TabItem}" x:Key="TabItemBase">
    <Setter Property="Cursor" Value="Hand" />
</Style>

<!-- Sub Style Setting-->
<Style TargetType="{x:Type TabItem}" x:Key="LTabEquipment" BasedOn="{StaticResource TabItemBase}">
    <Setter Property="Header">
        <Setter.Value>
            <StackPanel Orientation="Vertical">
                <Image Height="36" Source="pack://application:,,,/Images/gears.png" Width="36" Margin="0,5,0,0" />
                <TextBlock Text="Equipment" Margin="2,0,0,0" VerticalAlignment="Bottom" HorizontalAlignment="Center" />
            </StackPanel>
        </Setter.Value>
    </Setter>
</Style>

<Style TargetType="{x:Type TabItem}" x:Key="LTabHistory" BasedOn="{StaticResource TabItemBase}">
    <Setter Property="Header">
        <Setter.Value>
            <StackPanel Orientation="Vertical">
                <Image Height="36" Source="pack://application:,,,/Images/history.png" Width="36" Margin="0,5,0,0" />
                <TextBlock Text="History" Margin="2,0,0,0" VerticalAlignment="Bottom" HorizontalAlignment="Center" />
            </StackPanel>
        </Setter.Value>
    </Setter>
</Style>

<Style TargetType="{x:Type TabItem}" x:Key="HTabDBase" BasedOn="{StaticResource TabItemBase}">
    <Setter Property="Header">
        <Setter.Value>
            <StackPanel Orientation="Horizontal">
                <Image Height="14" Source="pack://application:,,,/Images/dbase.png" Width="14" Margin="0,0,0,0" HorizontalAlignment="stretch" VerticalAlignment="stretch" />
                <TextBlock Text="grid view" Margin="2,0,0,0" VerticalAlignment="center" HorizontalAlignment="center" />
            </StackPanel>
        </Setter.Value>
    </Setter>    
</Style>

然后在我的 MainWindow.xaml 中包含:

    <TabControl Grid.Row="2" Name="tabLeft" TabStripPlacement="Left">
        <TabItem x:Name="tabLeftEquipment" Style="{StaticResource LTabEquipment}">
            <TabControl Style="{StaticResource TabControlBase}" Name="tabTopEquipment" >
                <TabItem x:Name="tabTopEquipmentGridView" Style="{StaticResource HTabDBase}">
                </TabItem>
            </TabControl>
        </TabItem>
        <TabItem x:Name="tabLeftHistory" Style="{StaticResource LTabHistory}">
            <TabControl Height="Auto" Name="tabTopHistory" Width="Auto">
                <TabItem x:Name="tabTopHistoryGridView" Style="{StaticResource HTabDBase}" >
                </TabItem>
            </TabControl>
        </TabItem>

在设计时样式提供了我想要的外观,但在运行时出现异常:

'设置属性'System.Windows.FrameworkElement.Style'抛出异常。'

哪个指向线:

                <TabItem x:Name="tabTopEquipmentGridView" Style="{StaticResource HTabDBase}">

请帮助查找异常原因...谢谢!


我详细找到了以下内容,但仍然无法确定是哪个元素导致问题更正。

   Message=Specified element is already the logical child of another element. Disconnect it first.

【问题讨论】:

  • 你确定图片源路径在运行时正确吗?
  • 到目前为止我得到的最好的线索是它与 或 HTabDBase 被应用在多个位置有关。
  • @ashur668 我已经按原样使用了您的代码,并且运行良好。我在Window.Resources 中定义了所有样式。而且您必须在代码中执行其他操作。
  • 同意,我过度简化了我的原始条目。当在多个 TabItem 中使用 HTabDBase 样式时,该问题出现在 mainfest。
  • 我从 MainWindow.xaml 修改了上面的代码示例。

标签: wpf


【解决方案1】:

您可以通过在包含Images 的样式中使用x:Shared="False" 来解决此问题。默认情况下,所有资源都有x:Shared="True",这意味着 WPF 只为每个资源创建一个实例。因此,当任何对象使用StaticResource 或其他方式请求资源时,将返回该实例而不是创建新实例。这会导致您的情况出现问题,因为这里:

<TabItem x:Name="tabTopEquipmentGridView" Style="{StaticResource HTabDBase}">
</TabItem>

样式将图像的实例放在标题中。因此Image 成为TabItem 的子代。现在在这里:

<TabItem x:Name="tabTopHistoryGridView" Style="{StaticResource HTabDBase}" >
</TabItem>

您再次设置样式,这意味着您将相同的图像实例放入 tabItem 的可视化树中。但是图像已经有一个父级 => 抛出异常是因为UIElements 只能有一个父级..

样式并不意味着设置控件的内容。样式应该改变它的属性。但是x:Shared=False 修复了它:)

另一种更优雅的方式是设置HeaderTemplate 而不是Header。既然样式应该改变属性,它可以改变内容模板吗?是的,它可以。 (注意 ContentTemplate 不是 Template 这是控件本身的模板。这是您在答案中设置的内容。如果您只想“设置”内容,则应该设置 ContentTemplate。)示例:

<Setter Property="HeaderTemplate">
    <Setter.Value>
        <DataTemplate>
            <StackPanel Orientation="Vertical">
                <Image Height="36" Width="36" Margin="0,5,0,0" />
                <TextBlock Text="History" Margin="2,0,0,0" VerticalAlignment="Bottom" HorizontalAlignment="Center" />
            </StackPanel>
        </DataTemplate>
    </Setter.Value>
</Setter>

所以你不再需要x:SharedTemplates 不会遇到同样的问题,因为它不是共享的。为每个元素创建一个新的模板实例。

【讨论】:

  • 太棒了!使用 HeaderTemplate 效果很好,你对 x:Shared 的解释也很棒。非常感谢!
【解决方案2】:

第一次看的时候没掌握解决办法,但是在以下找到了最后的线索:

WPF TabItem Header Styling

使用 Template 属性和 ControlTemplate,而不是将样式应用于 Header 属性,防止了该问题。

修改后的样式代码

<!-- Base Style Setting-->
<Style TargetType="{x:Type TabControl}" x:Key="TabControlBase">
    <Setter Property="Height" Value="Auto" />
    <Setter Property="Width"  Value="Auto" />
</Style>

<Style TargetType="{x:Type TabItem}" x:Key="TabItemBase">
    <Setter Property="Cursor" Value="Hand" />
</Style>

<Style TargetType="{x:Type Image}" x:Key="VTabImage">
    <Setter Property="Height" Value="36" />
    <Setter Property="Width" Value="36" />
    <Setter Property="Margin" Value="0,5,0,0" />
</Style>

<!-- Sub Style Setting-->
<Style TargetType="{x:Type TabItem}" x:Key="LTabEquipment" BasedOn="{StaticResource TabItemBase}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type TabItem}">
                <StackPanel Orientation="Vertical">
                    <Image Height="36" Source="pack://application:,,,/Images/gears.png" Width="36" Margin="0,5,0,0" />
                    <TextBlock Text="Equipment" Margin="2,0,0,0" VerticalAlignment="Bottom" HorizontalAlignment="Center" />
                </StackPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

<Style TargetType="{x:Type TabItem}" x:Key="LTabHistory" BasedOn="{StaticResource TabItemBase}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type TabItem}">
                <StackPanel Orientation="Vertical">
                    <Image Height="36" Source="pack://application:,,,/Images/history.png" Width="36" Margin="0,5,0,0" />
                    <TextBlock Text="History" Margin="2,0,0,0" VerticalAlignment="Bottom" HorizontalAlignment="Center" />
                </StackPanel>
            </ControlTemplate>                    
        </Setter.Value>
    </Setter>
</Style>

<Style TargetType="{x:Type TabItem}" x:Key="HTabDBase" BasedOn="{StaticResource TabItemBase}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type TabItem}">  
                <StackPanel Orientation="Horizontal">
                    <Image Height="14" Source="pack://application:,,,/Images/dbase.png" Width="14" Margin="0,0,0,0" HorizontalAlignment="stretch" VerticalAlignment="stretch" />
                    <TextBlock Text="Grid View" Margin="2,0,0,0" VerticalAlignment="center" HorizontalAlignment="center" />
                </StackPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>    
</Style>

但这并不是一个理想的解决方案; 因为使用 ControlTemplate 会删除原始控件的所有默认样式和操作。

仍在寻找更好的解决方案。

【讨论】:

    【解决方案3】:

    我找到了另一种不触发异常的方法,但也不喜欢这个。

    当 HTabDBase 样式应用于应用程序中的多个 TabItem 时,似乎会发生异常。

    为了证明这一点,我复制/粘贴了两个副本并将它们的密钥更改为 HTabDBase1 和 HTabDBase2。然后我分别应用了每个。除了键之外,样式定义是相同的。

    <Style TargetType="{x:Type TabItem}" x:Key="HTabDBase2" BasedOn="{StaticResource TabItemBase}">
        <Setter Property="Header">
            <Setter.Value>
                <StackPanel Orientation="Horizontal">
                    <Image Height="14" Source="pack://application:,,,/Images/dbase.png" Width="14" Margin="0,0,0,0" HorizontalAlignment="stretch" VerticalAlignment="stretch" />
                    <TextBlock Text="grid view" Margin="2,0,0,0" VerticalAlignment="center" HorizontalAlignment="center" />
                </StackPanel>
            </Setter.Value>
        </Setter>
    </Style>
    

    然后在 MainWindow.xaml:

    <TabControl Grid.Row="2" Name="tabLeft" TabStripPlacement="Left">
        <TabItem x:Name="tabLeftEquipment" Style="{StaticResource LTabEquipment}">
            <TabControl Style="{StaticResource TabControlBase}" Name="tabTopEquipment" >
                <TabItem x:Name="tabTopEquipmentGridView" Style="{StaticResource HTabDBase1}">
                </TabItem>
            </TabControl>
        </TabItem>
        <TabItem x:Name="tabLeftHistory" Style="{StaticResource LTabHistory}">
            <TabControl Height="Auto" Name="tabTopHistory" Width="Auto">
                <TabItem x:Name="tabTopHistoryGridView" Style="{StaticResource HTabDBase2}" >
                </TabItem>
            </TabControl>
        </TabItem>
    

    但这种解决方案似乎违背了创建样式的大部分目的; 即我创建的样式可以在任何位置重复使用,但是在多个位置使用它会导致运行时错误。

    【讨论】:

      猜你喜欢
      • 2011-04-28
      • 1970-01-01
      • 2011-08-30
      • 1970-01-01
      • 2016-06-26
      • 2018-02-13
      • 2014-12-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多