设置ContentPresenter内所有元素的样式

7

我重写了WPF扩展器的模板。 头部包含ContentPresenter。

<ContentPresenter x:Name="HeaderContent"
                  Grid.Column="1"
                  Margin="0,0,4,0"
                  HorizontalAlignment="Left"
                  VerticalAlignment="Center"
                  RecognizesAccessKey="True"
                  SnapsToDevicePixels="True"
                  >
    <ContentPresenter.Resources>
        <Style BasedOn="{StaticResource Expanderheader-Naming}" 
               TargetType="{x:Type TextBlock}" />
     </ContentPresenter.Resources>
</ContentPresenter>

我尝试为所有TextBlock添加我的样式。 如果将标题设置为属性,则我的样式有效:

<Expander Header="HelloWorld">

但是如果我尝试用另一种方式设置它,就无法实现。
<Expander>
    <Expander.Header>
        <Grid x:Name="MyGrid">
            <TextBlock>Hello Man</TextBlock>
        </Grid>  
    </Expander.Header>
</Expander>

如何为 ContentPresenter 中的任何 TextBlock 设置此样式?
1个回答

14
您遇到了WPF中典型的样式继承问题。
控件在被初始化时会查找其样式。控件寻找其样式的方式是向上移动逻辑树,并询问逻辑父对象是否在其资源字典中存储了适当的样式。
为了让您明白在示例中您错误的地方,我们可以这样想:
在第一个示例中,“Header”仅仅存储了“HelloWorld”,而当控件被初始化时,“HelloWorld”将被注入到ContentPresenter中。这种方法使ContentPresenter成为逻辑父级,因此样式可以正确应用,因为可以找到样式。
在第二个示例中,您创建了一个Grid,在Grid内部有一个TextBlock。
在控件初始化时,TextBlock的逻辑父级是Grid,而Grid的逻辑父级是折叠板本身。当WPF为TextBlock查找样式时,它将询问TextBlock的逻辑父级是否在其资源中有适当的样式,答案将为否定。在Grid.Resources和Expander.Resources中均不存在TextBlock的适当样式。
在这种情况下,适当的样式应该在ContentPresenter中,只是ContentPresenter不是逻辑树的一部分。
这就是您在第二个示例中失去样式的原因。
为了解决这个问题,我建议您坚持使用第一个示例或更改样式存储的位置。通常,所有样式都应存储在Window.Resources中。
编辑2 请仔细查看以下示例:
<Window.Resources>
    <Style x:Key="textBlockStyle" TargetType="TextBlock">
        <Setter Property="Background" Value="Blue"/>
    </Style>


    <Style TargetType="Button">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    <ContentPresenter>
                        <ContentPresenter.Resources>
                            <Style TargetType="TextBlock" BasedOn="{StaticResource textBlockStyle}"/>
                        </ContentPresenter.Resources>
                    </ContentPresenter>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>
<StackPanel>
    <Button Content="Yay, it worked!" />
    <Button>
        <Grid>
            <TextBox Text="It doesn't work this way!"/>
        </Grid>
    </Button>
    <Button>
        <Grid>
            <Grid.Resources>
                <Style TargetType="TextBlock" BasedOn="{StaticResource textBlockStyle}"></Style>
            </Grid.Resources>
            <TextBlock Text="Yay it works again! Woop Woop"/>
        </Grid>
    </Button>
</StackPanel>

抱歉,也许我理解有误,但这是否意味着如果我使用以下代码: <Style TargetType="{x:Type Grid}"><Style.Resources> <Style BasedOn="{StaticResource Expanderheader-Naming}" TargetType="{x:Type TextBlock}" />` 它应该可以工作? - user1706449
1
我会为您创建一个示例,并将代码粘贴在我的答案中。请给我几分钟时间。 - dev hedgehog
看这里,你在之前的评论中又用错了。 - dev hedgehog
谢谢您的回复,但问题是我只能更改模板,不能更改MainWindow中的任何内容,并且我应该为展开器标题中的任何文本框添加样式。 请不要问我为什么))) 但这就是规则))) 我希望您有一些想法) - user1706449
让我们在聊天中继续这个讨论。点击此处进入聊天室 - user1706449
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接