WPF:如何拥有默认使用系统按钮背景的自定义按钮模板?

发布于 2024-08-13 16:54:15 字数 4326 浏览 1 评论 0原文

我正在创建一种更改按钮的 ControlTemplate 的样式(它实际上在右侧添加了箭头,以便该按钮看起来像下拉按钮(在 wpf 中缺少))。

在模板内部,我放置了实际的按钮(因为我需要结果仍然像按钮一样 - 我只能更改 ContentTemplate,但我需要将实际内容与箭头一起显示,并将 ContentPresenter 放入 ContentTemplate 中会产生堆栈溢出 - wpf 只是将模板扩展到演示者并继续),以及箭头。

我的问题是我希望用户能够更改按钮的背景,因此我需要绑定 Background="{TemplateBinding Background}"。这样,用户就必须始终提供背景,否则背景将为空。 为了防止这种情况,我知道我需要为背景提供默认值,因此我添加了

问题是,什么应该是这个设置器的值?我假设 wpf 的内置样式会为每个应用程序自动加载,并且我研究了 aero.normalcolor.xaml,其中它们提供了 ButtonNormalBackground 样式,稍后将其用作默认按钮样式 (aero.normalcolor.xaml,第 47 行)。

正是我想要的,但是,当我使用这个设置器时,找不到静态资源。然后我将其更改为 DynamicResource,但在这种情况下,按钮的背景保持透明 - 不使用 ButtonNormalBackground!

我应该如何提供系统按钮外观作为默认值?谢谢你!

PS:BorderBrush、BorderThickness 的 dtto - 天哪,看来我不被允许使用 WPF 作者一直使用的技巧:/

我的风格:

<Style TargetType="{x:Type ToggleButton}" x:Key="DropDownArrowStyle">
    <Setter Property="Background" Value="{StaticResource ButtonNormalBackground}"/>
    <Setter Property="ToggleButton.Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ToggleButton}">
                <ToggleButton 
                    x:Name="PART_ToggleButton"
                    Margin="{TemplateBinding Margin}"
                    Padding="{TemplateBinding Padding}"
                    HorizontalAlignment="Stretch"
                    VerticalAlignment="Stretch"
                    HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
                    VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
                    IsEnabled="{TemplateBinding IsEnabled}"
                    IsChecked="{Binding IsChecked, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"
                    ContextMenu="{TemplateBinding ContextMenu}"
                    Background="{TemplateBinding Background}"
                    BorderBrush="{TemplateBinding BorderBrush}"
                    BorderThickness="{TemplateBinding BorderThickness}"
                    Foreground="{TemplateBinding Foreground}"
                    FocusVisualStyle="{TemplateBinding FocusVisualStyle}"
                    ClickMode="{TemplateBinding ClickMode}"
                    >
                    <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*" />
                            <ColumnDefinition Width="Auto" />
                        </Grid.ColumnDefinitions>
                        <ContentPresenter
                            x:Name="ButtonContentPresenter"
                            HorizontalAlignment="Left"
                            VerticalAlignment="Stretch"
                            Margin="{TemplateBinding Padding}"
                            Content="{TemplateBinding Content}"
                            Grid.Column="0"
                            />
                        <Border 
                            x:Name="PART_DownArrowBorder"
                            HorizontalAlignment="Stretch"
                            VerticalAlignment="Stretch"
                            Background="Transparent"
                            Focusable="False"
                            Grid.Column="1"
                            >
                            <Path 
                                Focusable="False"
                                x:Name="PART_DownArrow"
                                Data="M 3,0 L 6.5,4 L 10,0" 
                                Width="12" 
                                HorizontalAlignment="Right"
                                VerticalAlignment="Center"
                                Fill="Black" SnapsToDevicePixels="True"
                                >
                            </Path>
                        </Border>
                    </Grid>
                </ToggleButton>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

I am creating a style that changes a ControlTemplate of a Button (it actually adds arrow on the right, so that the button looks like dropdown button (which is missing in wpf)).

Inside of template, I put the actual button (because I need the result to still be like button - I could change only ContentTemplate, but I need to display the actual content together with arrow, and putting ContentPresenter inside ContentTemplate yields stack overflow - wpf just expands the template into the presenter and goes on and on), together with arrow.

My problem is that I would like the user to be able to change button's background, so I need to bind Background="{TemplateBinding Background}". With this, the user would have to always provide the background, otherwise it would be null.
To prevent this, I understand I need to provide default value for the background, so I added <Setter Property="Background" Value="default Background goes here"/>

The question is, what should be a value of this setter? I assume that wpf's built-in styles are loaded automatically for every application, and I have looked into aero.normalcolor.xaml, where they provide ButtonNormalBackground style, and later use it as default button style <Setter Property="Background" Value="{StaticResource ButtonNormalBackground}"/> (aero.normalcolor.xaml, line 47).

Exactly what I wanted, however, when I use this setter, the static resource is not found. I then changed it to DynamicResource, but in that case, the button's background stays transparent - the ButtonNormalBackground isn't used!

How should I provide system's button look as default value? Thank you!

PS: dtto for BorderBrush, BorderThickness - geez, it seems that I am not allowed the tricks that WPF authors use all the time :/

My style:

<Style TargetType="{x:Type ToggleButton}" x:Key="DropDownArrowStyle">
    <Setter Property="Background" Value="{StaticResource ButtonNormalBackground}"/>
    <Setter Property="ToggleButton.Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ToggleButton}">
                <ToggleButton 
                    x:Name="PART_ToggleButton"
                    Margin="{TemplateBinding Margin}"
                    Padding="{TemplateBinding Padding}"
                    HorizontalAlignment="Stretch"
                    VerticalAlignment="Stretch"
                    HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
                    VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
                    IsEnabled="{TemplateBinding IsEnabled}"
                    IsChecked="{Binding IsChecked, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"
                    ContextMenu="{TemplateBinding ContextMenu}"
                    Background="{TemplateBinding Background}"
                    BorderBrush="{TemplateBinding BorderBrush}"
                    BorderThickness="{TemplateBinding BorderThickness}"
                    Foreground="{TemplateBinding Foreground}"
                    FocusVisualStyle="{TemplateBinding FocusVisualStyle}"
                    ClickMode="{TemplateBinding ClickMode}"
                    >
                    <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*" />
                            <ColumnDefinition Width="Auto" />
                        </Grid.ColumnDefinitions>
                        <ContentPresenter
                            x:Name="ButtonContentPresenter"
                            HorizontalAlignment="Left"
                            VerticalAlignment="Stretch"
                            Margin="{TemplateBinding Padding}"
                            Content="{TemplateBinding Content}"
                            Grid.Column="0"
                            />
                        <Border 
                            x:Name="PART_DownArrowBorder"
                            HorizontalAlignment="Stretch"
                            VerticalAlignment="Stretch"
                            Background="Transparent"
                            Focusable="False"
                            Grid.Column="1"
                            >
                            <Path 
                                Focusable="False"
                                x:Name="PART_DownArrow"
                                Data="M 3,0 L 6.5,4 L 10,0" 
                                Width="12" 
                                HorizontalAlignment="Right"
                                VerticalAlignment="Center"
                                Fill="Black" SnapsToDevicePixels="True"
                                >
                            </Path>
                        </Border>
                    </Grid>
                </ToggleButton>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

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

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

发布评论

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

评论(1

鹿港巷口少年归 2024-08-20 16:54:15

您需要定义要使用的颜色并引用系统颜色:

<SolidColorBrush 
   Color="{DynamicResource {x:Static SystemColors.HighlightColorKey}}"
   x:Key="ButtonLinkBackground"/>

<Grid Background="{DynamicResource {x:Static SystemColors.DesktopBrushKey}}"/>

有关可用系统颜色的更多信息 如何使用 XAML 在 WPF 中列出颜色?

You need to define the colors you want to use and reference the system colors:

i.e.

<SolidColorBrush 
   Color="{DynamicResource {x:Static SystemColors.HighlightColorKey}}"
   x:Key="ButtonLinkBackground"/>

or

<Grid Background="{DynamicResource {x:Static SystemColors.DesktopBrushKey}}"/>

More info on SystemColors available How can I list colors in WPF with XAML?

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