如何为WPF Expander Header设置样式?

59

我想在WPF Expander的标题栏应用一种样式。下面的XAML中,我有一个Expander,但样式适用于所有内容而不仅仅是标题栏。

谢谢。

<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="640"
>
    <StackPanel>
        <StackPanel.Resources>
            <Style TargetType="Expander">
                <Style.Resources>
                    <LinearGradientBrush x:Key="BackBrush" StartPoint="0.5,0" EndPoint="0.5,1">
                        <GradientStop Color="#EF3132" Offset="0.1" />
                        <GradientStop Color="#D62B2B" Offset="0.9" />
                    </LinearGradientBrush>
                </Style.Resources>
                <Setter Property="Background" Value="{StaticResource BackBrush}"/>
            </Style>
        </StackPanel.Resources>
        <Expander>
            <StackPanel>
                <TextBlock>Bike</TextBlock>
                <TextBlock>Car</TextBlock>
                <TextBlock>Truck</TextBlock>
            </StackPanel>
        </Expander>
    </StackPanel>
</Page>
3个回答

62

我结合了Josh SmithMSDN的一些XAML,得出了一个解决方案。确实,该控件(至少是标题)必须重新模板化。

<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400">
    <StackPanel>
        <StackPanel.Resources>

            <Style TargetType="Border" x:Key="RacePitBorderStyle" >
                <Style.Resources>
                    <LinearGradientBrush x:Key="BackBrush" StartPoint="0.5,0" EndPoint="0.5,1">
                        <GradientStop Color="#EF3132" Offset="0.1" />
                        <GradientStop Color="#D62B2B" Offset="0.9" />
                    </LinearGradientBrush>
                </Style.Resources>
                <Setter Property="Background" Value="{StaticResource BackBrush}"/>
            </Style>

            <DataTemplate x:Key="titleText">
                <Border Style="{StaticResource RacePitBorderStyle}" Height="24">
                    <TextBlock Text="{Binding}" 
                        Margin="4 0"
                        VerticalAlignment="Center"
                        Foreground="White"
                        FontSize="11" 
                        FontWeight="Normal"
                        Width="{Binding
                        RelativeSource={RelativeSource
                        Mode=FindAncestor,
                        AncestorType={x:Type Expander}},
                        Path=ActualWidth}"
                        TextWrapping="Wrap"/>
                </Border>
            </DataTemplate>

            <Style TargetType="{x:Type Expander}">
                <Setter Property="HeaderTemplate" Value="{StaticResource titleText}"/>
            </Style>

        </StackPanel.Resources>

        <Expander Name="hcontCtrl" Header="This is the header.">
            <StackPanel>
                <TextBox>This is a textbox</TextBox>
                <Button>A button</Button>
            </StackPanel>
        </Expander>

    </StackPanel>
</Page>

2
我发现获取扩展器宽度是一个真正的问题,而你的代码可以解决这个问题。它在xamlpad中完美运行。然而,在我的代码中,它却不能正常工作,并且导致了可怕的图形延迟。 Width="{Binding RelativeSource{RelativeSource Mode=FindAncestor,AncestorType={x:Type Expander}}, Path=ActualWidth}"> 通过添加上述内容,它可以工作,但会出现延迟。如果我将其删除或更改Path=Width,则无法正常工作并且延迟消失。 - JonWillis
1
正是我所需要的。谢谢!有时深入研究XAML真是一件头疼的事情。 - Ignacio Soler Garcia
4
建议移除样式并直接在可展开面板上使用“HeaderTemplate”属性。这样可以保留默认样式。 - Natxo
这种样式看起来在数据网格分组标题上很好,但它需要很多资源。使用此样式后,我在单击数据网格行并选择它的瞬间会有1秒的滞后。没有这种样式,一切都很快。我的数据网格中只有300行。 - Alexandru Dicu

25

我认为Vasile的回答是在正确的方向上,但似乎做了比原帖需要更多的事情。原始问题只是要求改变标题的背景色。虽然所提出的更改确实做到了这一点,但它也做了其他事情。

其中一个其他的事情是用TextBlock替换默认实现(ContentPresenter)。那么当我们稍后改变Expander以使标题更加复杂时会发生什么呢?也许像这样:

<Expander>
    <Expander.Header>
        <StackPanel>
            <Border height="5" width="5" Foreground="Blue"/>
            <TextBlock>Ha!</TextBlock>
        </StackPanel>
    </Expander.Header>
</Expander>

我不知道,但这不是好事。相反,我认为我们想要保持简单。

<DataTemplate x:Key="expanderHeader">
    <ContentPresenter
        Content={Binding}
        TextBlock.Background={StaticResource myBrush}/>
</DataTemplate>

<Style TargetType="Expander">
    <Setter Property="HeaderTemplate" Value="{StaticResource expanderHeader}"/>
</Style>

这样,当有人在我们的样式扩展器中输入非纯文本内容时,我们就不会出现错误。如果您想确保将其与背景整体包装,这可能是期望的,那么应该这样做:

<DataTemplate x:Key="expanderHeader">
    <Border Background={StaticResource myBrush}>
        <ContentPresenter Content={Binding}/>
    </Border>
</DataTemplate>

7

这取决于您想要样式化的内容 - 您可以样式化其中的任何部分。如果您想更改标题中的内容,请将所有UI放置在Expander.Header属性中,它将显示在标题区域。

如果那不能满足您的需求,您可能需要重新设计控件模板。请在WPF中查看预装的控件模板here


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