应用样式时的XamlParse异常

时间:2016-04-20 15:03:58

标签: wpf

这是第一个使用WPF和Styles的项目。 开发工具是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>

在设计时,样式提供了我想要的外观,但在运行时我得到一个例外:

&#39;设置属性&#39; System.Windows.FrameworkElement.Style&#39;抛出异常。&#39;

指向哪一行:

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

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

我详细了解了以下内容,但仍然无法确定导致问题纠正的元素。

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

3 个答案:

答案 0 :(得分:1)

我第一次读到它时没有掌握解决方案,但找到了最后的线索:

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会删除原始控件的所有默认样式和操作。

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

答案 1 :(得分:1)

您可以使用x:Shared =&#34; False&#34;来解决此问题。在包含图像的样式中。默认情况下,所有资源都有x:Shared =&#34; True&#34;这意味着WPF只创建每个资源的单个实例。因此,当任何对象使用StaticResource或其他任何对象请求资源时,将返回该实例而不是创建新实例。这会导致您的情况出现问题,因为这里: &lt; TabItem x:Name =&#34; tabTopEquipmentGridView&#34; Style =&#34; {StaticResource HTabDBase}&#34;&gt; &LT; / TabItem的&GT; 样式将图像的实例放在标题内。因此,Image成为TabItem的子级。现在这里: &lt; TabItem x:Name =&#34; tabTopHistoryGridView&#34; Style =&#34; {StaticResource HTabDBase}&#34; &GT; &LT; / TabItem的&GT; 再次设置样式,这意味着您将相同的图像实例放在tabItem的可视树中。但图像已经有一个父=>抛出异常是因为UIElements只能有一个父... 样式不是为了设置控件的内容。样式应该改变它的属性。但是x:Shared = False修复它:) 另一个更优雅的方法是设置HeaderTemplate而不是Header。由于样式应该更改属性,它可以更改内容模板吗?是的,它可以。 (注意ContentTemplate不是模板,它是控件本身的模板。这是你在答案中设置的。如果你只想要&#34;样式&#34;内容,你应该设置ContentTemplate。)示例: &lt; Setter Property =&#34; HeaderTemplate&#34;&gt;     &LT; Setter.Value&GT;         &LT;&的DataTemplate GT;             &lt; StackPanel Orientation =&#34; Vertical&#34;&gt;                 &lt;图像高度=&#34; 36&#34;宽度=&#34; 36&#34;余量=&#34; 0,5,0,0&#34; /&GT;                 &lt; TextBlock Text =&#34; History&#34;余量=&#34; 2,0,0,0&#34; VerticalAlignment =&#34;底部&#34;的Horizo​​ntalAlignment =&#34;中心&#34; /&GT;             &LT; / StackPanel中&GT;         &LT; / DataTemplate中&GT;     &LT; /Setter.Value> &LT; /设置器&GT; 所以你不再需要x:共享。模板不会遇到同样的问题,因为它没有共享。为每个元素创建一个新的模板实例。

答案 2 :(得分:0)

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

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

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