WPF 样式/模板继承

发布于 2024-11-29 17:03:06 字数 4706 浏览 1 评论 0原文

我目前正在尝试学习 WPF,并研究通过使用样式使默认的 .Net 控件看起来有所不同。尽管下面的所有代码都是 WPF 标记,但使用 C# 作为我的首选语言。

我今天使用新主题设置了 gmail(见下图),从而为自己设定了可以在 WPF 中完成的挑战。

New GMail Button

我设法实现的是通过使用创建中间按钮 Spam具有控件模板和触发器的样式。

左右按钮非常相似,但只有两处不同。它们的角半径为 1,左侧或右侧边距为 15,而中间按钮将它们都设置为 0。

问题!

Q1。而不是复制整个样式并仅更改这两个属性,可以通过某种类型的继承来完成吗?右侧和左侧按钮基于现有样式,但它使这两个视觉变化。我在创建新样式时已经尝试过 BasedOn 属性,但无法编辑所需的属性。

Q2. 样式是在 WPF 中解决此问题的正确方法吗?在 WinForms 中,您会希望创建一个自定义控件,该控件具有链接到枚举的可见属性,即您单击按钮,样式选项可能为“左”、“中”、“右”。

Q3。最后一个最困难的问题。是否可以制作它,如果一个按钮应用了我的样式。然后当你将其背景颜色设置为蓝色时。然后按钮保持渐变,但不再是灰白色,而是蓝色阴影。即背景线性渐变画笔基于而不是覆盖已应用于按钮的背景颜色。或者这些是否需要定义单独的样式。我个人认为如果没有某种类型的代码就可以实现这一点,即从 WPF 标记中的单个画笔制作渐变画笔。

即按钮如下,一个蓝色按钮和一个灰色/普通按钮

Google Buttons 2

MyStyle

<Style x:Key="GoogleMiddleButton" TargetType="{x:Type Button}">
        <Setter Property="Background">
            <Setter.Value>
                <LinearGradientBrush StartPoint="0,1" EndPoint="0,0">
                    <GradientStop Color="#F1F1F1" Offset="0"/>
                    <GradientStop Color="#F5F5F5" Offset="1"/>
                </LinearGradientBrush>
            </Setter.Value>
        </Setter>
        <Setter Property="Foreground" Value="#666666"/>
        <Setter Property="FontFamily" Value="Arial"/>
        <Setter Property="FontSize" Value="13"/>
        <Setter Property="FontWeight" Value="Bold"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    <Border Name="dropShadowBorder"
                        BorderThickness="0,0,0,1"
                        CornerRadius="1"
                        >
                        <Border.BorderBrush>
                            <SolidColorBrush Color="#00000000"/>
                        </Border.BorderBrush>
                    <Border Name="border" 
                    BorderThickness="{TemplateBinding BorderThickness}"
                    Padding="{TemplateBinding Padding}" 
                    CornerRadius="0" 
                    Background="{TemplateBinding Background}">
                        <Border.BorderBrush>
                            <SolidColorBrush Color="#D8D8D8"/>
                        </Border.BorderBrush>
                        <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
                                  VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                        </Border>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter Property="BorderBrush" TargetName="border">
                                <Setter.Value>
                                    <SolidColorBrush Color="#939393"/>
                                </Setter.Value>
                            </Setter>
                            <Setter Property="BorderBrush" TargetName="dropShadowBorder">
                                <Setter.Value>
                                    <SolidColorBrush Color="#EBEBEB"/>
                                </Setter.Value>
                            </Setter>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Style.Triggers>
            <Trigger Property="IsMouseOver" Value="True">
                <Setter Property="Foreground" Value="#333333"/>
            </Trigger>
            <Trigger Property="IsPressed" Value="True">
                <Setter Property="Background">
                    <Setter.Value>
                        <LinearGradientBrush StartPoint="0,1" EndPoint="0,0">
                            <GradientStop Color="#F1F1F1" Offset="1"/>
                            <GradientStop Color="#F5F5F5" Offset="0"/>
                        </LinearGradientBrush>
                    </Setter.Value>
                </Setter>
            </Trigger>
        </Style.Triggers>
    </Style>

ps If如果您在上面的 WPF 中发现任何初学者错误,请随时向我指出。

I'm trying to learn WPF at the moment, and looking into making the default .Net control look different through the use of style. Using C# as my preferred language although all the code below is WPF markup.

I setup gmail today with the new theme, (see image below) and thus set my self the challenge, could be done in WPF.

New GMail buttons

What I have managed to achieve is to create the middle button Spam through the use of a style with a control template and triggers.

The right and left buttons are very similar but with only 2 differences. They have a corner radius of 1 and margin of 15 on the left or right sides, whilst the middle button has them both set to 0.

Questions!

Q1. Rather than copying the entire style and changing just those 2 attributes, can it be done via some type of inheritance. Where by the right and left buttons are based on an existing style but it makes those 2 visual changes. I have already tried the BasedOn property when creating a new style but was unable to edit the attributes needed.

Q2. Are styles the right way to address this problem in WPF. In WinForms you would look to create a custom control, which has a visible property linked to an enum, i.e. you click on the button and the style options maybe Left, Middle, Right.

Q3. The most difficult question til last. Is it possible to make it, so if a button has my style applied to it. Then when you set its background colour to say blue. Then the button maintains the gradients but instead of them been off-white they are now a shade of blue. i.e. the background linear gradient brush is based on, rather than overwrites the background colour that has been applied to the button. Or do these need to have separate styles defined. I personally cannot see without some type of code behind that this could be achieved, that is making gradient brushes from a single brush in WPF markup.

i.e. buttons as below a blue button and a grey/normal button

Google buttons 2

MyStyle

<Style x:Key="GoogleMiddleButton" TargetType="{x:Type Button}">
        <Setter Property="Background">
            <Setter.Value>
                <LinearGradientBrush StartPoint="0,1" EndPoint="0,0">
                    <GradientStop Color="#F1F1F1" Offset="0"/>
                    <GradientStop Color="#F5F5F5" Offset="1"/>
                </LinearGradientBrush>
            </Setter.Value>
        </Setter>
        <Setter Property="Foreground" Value="#666666"/>
        <Setter Property="FontFamily" Value="Arial"/>
        <Setter Property="FontSize" Value="13"/>
        <Setter Property="FontWeight" Value="Bold"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    <Border Name="dropShadowBorder"
                        BorderThickness="0,0,0,1"
                        CornerRadius="1"
                        >
                        <Border.BorderBrush>
                            <SolidColorBrush Color="#00000000"/>
                        </Border.BorderBrush>
                    <Border Name="border" 
                    BorderThickness="{TemplateBinding BorderThickness}"
                    Padding="{TemplateBinding Padding}" 
                    CornerRadius="0" 
                    Background="{TemplateBinding Background}">
                        <Border.BorderBrush>
                            <SolidColorBrush Color="#D8D8D8"/>
                        </Border.BorderBrush>
                        <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
                                  VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                        </Border>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter Property="BorderBrush" TargetName="border">
                                <Setter.Value>
                                    <SolidColorBrush Color="#939393"/>
                                </Setter.Value>
                            </Setter>
                            <Setter Property="BorderBrush" TargetName="dropShadowBorder">
                                <Setter.Value>
                                    <SolidColorBrush Color="#EBEBEB"/>
                                </Setter.Value>
                            </Setter>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Style.Triggers>
            <Trigger Property="IsMouseOver" Value="True">
                <Setter Property="Foreground" Value="#333333"/>
            </Trigger>
            <Trigger Property="IsPressed" Value="True">
                <Setter Property="Background">
                    <Setter.Value>
                        <LinearGradientBrush StartPoint="0,1" EndPoint="0,0">
                            <GradientStop Color="#F1F1F1" Offset="1"/>
                            <GradientStop Color="#F5F5F5" Offset="0"/>
                        </LinearGradientBrush>
                    </Setter.Value>
                </Setter>
            </Trigger>
        </Style.Triggers>
    </Style>

p.s. If you spot any beginner mistakes in the WPF above, feel free to point them out to me.

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

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

发布评论

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

评论(3

情深如许 2024-12-06 17:03:06

我过去通过定义一个名为 ExtendedProperties.CornerRadius 的附加属性来完成此操作。然后我可以按照我的风格设置它:

<Style TargetType="Button">
    <Setter Property="local:ExtendedProperties.CornerRadius" Value="0"/>
    ...

并在模板中使用它:

<Border CornerRadius="{Binding Path=(local:ExtendedProperties.CornerRadius), RelativeSource={RelativeSource TemplatedParent}">

然后我可以以与覆盖任何其他属性相同的方式在本地覆盖它:

<Button Content="Archive" local:ExtendedProperties.CornerRadius="5,0,0,5"/>
<Button Content="Span"/>
<Button Content="Delete" local:ExtendedProperties.CornerRadius="0,5,5,0"/>

在我的情况下,这给了我(显然,我的主题是黑暗的):

< img src="https://i.sstatic.net/4ZBaF.png" alt="在此处输入图像描述">

只需调整几个主题的附加属性,我就创建了以下效果:

在此处输入图像描述

这种方法的优点是无需子类化 Button。您还可以使用相同的附加属性来定义其他控件(例如 TextBox)的角半径。当然,您不仅限于圆角半径。您可以为特定于您的主题但基本控件上不存在的各种事物定义附加属性。

缺点是它是附加财产,因此更难发现。记录你的主题将在这方面有所帮助。

因此,回答您的具体问题:

Q1。是的,看我上面的回答。您可以在本地覆盖或定义覆盖该属性的新样式。

Q2。这是一个灰色地带。在我看来,如果纯粹是视觉上的(而不是行为上的),那么风格就是正确的选择。当然,如果它失控,您可能希望对所有内置控件进行子类化并添加您的特定属性。但这会使您的主题更难重用,并且您的应用程序开发起来更加繁重(因为您需要使用您的控件集而不是标准控件集)。

Q3。我想说这在代码中是可能的,但作为控制消费者使用并不直观。我认为你最好定义额外的附加属性 - 例如。 ExtendedProperties.HoverBackgroundExtendedProperties.PressedBackground - 并以完全相同的方式使用模板中的那些内容。然后,当您的控件处于各种状态时,您的控件的使用者可以更好地控制所使用的画笔。我过去曾这样做过,但使用了更通用的属性名称(SecondaryBackgroundTernaryBackground),因此我可以在其他上下文中重用这些属性。再次强调,记录你的主题很有帮助。

I've done this in the past by defining an attached property called ExtendedProperties.CornerRadius. I can then set it in my style:

<Style TargetType="Button">
    <Setter Property="local:ExtendedProperties.CornerRadius" Value="0"/>
    ...

And use it from within the template:

<Border CornerRadius="{Binding Path=(local:ExtendedProperties.CornerRadius), RelativeSource={RelativeSource TemplatedParent}">

I might then override it locally in the same way I override any other property:

<Button Content="Archive" local:ExtendedProperties.CornerRadius="5,0,0,5"/>
<Button Content="Span"/>
<Button Content="Delete" local:ExtendedProperties.CornerRadius="0,5,5,0"/>

In my case, this gives me (obviously, my theme is dark):

enter image description here

And just by tweaking a couple of my theme's attached properties, I created this effect:

enter image description here

The advantage of this approach is that there's no need to subclass Button. You can also use that same attached property to define corner radii for other controls (such as TextBox). And you're not limited to just corner radius, of course. You could define attached properties for all sorts of things specific to your theme that aren't present on base controls.

The disadvantage is that it's an attached property and thus harder to discover. Documenting your theme will help in this respect.

So, to answer your specific questions:

Q1. Yes, see my answer above. You can either override locally or define new styles that override the property.

Q2. It's a gray area. In my opinion, if it's purely visual (not behavioural) then styles are the way to go. Of course, if it gets out of hand you may instead wish to subclass all the built-in controls and add your specific properties. But that makes your theme harder to re-use and your application more onerous to develop (because you need to use your control set rather than the standard ones).

Q3. I'd say it's possible in code, but not intuitive to use as a control consumer. I think you'd be better off defining extra attached properties - eg. ExtendedProperties.HoverBackground, ExtendedProperties.PressedBackground - and using those from your template in exactly the same way. Then consumers of your control then have more control over the brushes used when your control is in its various states. I've done this in the past but have used more generic property names (SecondaryBackground, TernaryBackground) so I can reuse those properties in other contexts. Again, documenting your theme is helpful.

姐不稀罕 2024-12-06 17:03:06

Q1:据我所知,还没有

Q2:我想说样式是可行的方法,您当然可以创建自己的类,该类派生自按钮,并根据左、中、右选择右角半径。

Q3:应该可以使用自定义值转换器和您自己的风格。

总之。在这种情况下,我可能想将背景渐变和角半径放在周围的堆栈面板上。按钮对于文本来说是透明的。这样您就不必处理各个按钮上的圆角半径。

编辑:添加代码和上面 Q3 答案的样式。至OP;我不确定这正是您想要的,但也许这里有一些您可能感兴趣的东西。

我对您的解释是您想要将按钮背景设置为某种颜色,但它应该呈现为基于该颜色的线性渐变。其他海报提到了不透明蒙版,这根本不是一个坏主意。我想我展示了如何使用自定义值转换器来做到这一点。

我的想法是创建一个自定义值转换,将纯色画笔转换为线性渐变画笔。然后我使用此转换器将按钮背景颜色从纯色画笔转换为线性渐变画笔。

这是自定义值转换器:

class SolidColorBrushToGradientConverter : IValueConverter
{
    const float DefaultLowColorScale = 0.95F;

    public object Convert (object value, Type targetType, object parameter, CultureInfo culture)
    {
        var solidColorBrush = value as SolidColorBrush;

        if (!targetType.IsAssignableFrom (typeof (LinearGradientBrush)) || solidColorBrush == null)
        {
            return Binding.DoNothing;
        }

        var lowColorScale = ParseParameterAsDouble (parameter);

        var highColor = solidColorBrush.Color;
        var lowColor = Color.Multiply (highColor, lowColorScale);
        lowColor.A = highColor.A;

        return new LinearGradientBrush (
            highColor,
            lowColor,
            new Point (0, 0),
            new Point (0, 1)
            );
    }

    static float ParseParameterAsDouble (object parameter)
    {
        if (parameter is float)
        {
            return (float)parameter;
        }
        else if (parameter is string)
        {
            float result;
            return float.TryParse(
                (string) parameter, 
                NumberStyles.Float, 
                CultureInfo.InvariantCulture, 
                out result
                        )
                        ? result
                        : DefaultLowColorScale
                ;
        }
        else
        {
            return DefaultLowColorScale;
        }
    }

    public object ConvertBack (object value, Type targetType, object parameter, CultureInfo culture)
    {
        return Binding.DoNothing;
    }
}

然后我以从您那里复制的样式引用它(基本上相同,但我对其进行了一些重组),重要的行部分是这样的:

Background="{Binding Path=Background,Mode=OneWay,RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource SolidColorBrushToGradientConverter}, ConverterParameter=0.95}"

这意味着我们绑定到模板化父背景(即按钮.Background),我们使用参数为 0.95 的转换器 SolidColorBrushToGradientConverter (这决定了“低”颜色与“高”颜色相比应该深多少)。

完整风格:

<local:SolidColorBrushToGradientConverter x:Key="SolidColorBrushToGradientConverter" />

<Style x:Key="GoogleMiddleButton" TargetType="{x:Type Button}">
    <Setter Property="Background" Value="#F5F5F5" />
    <Setter Property="Foreground" Value="#666666"/>
    <Setter Property="FontFamily" Value="Arial"/>
    <Setter Property="FontSize" Value="13"/>
    <Setter Property="FontWeight" Value="Bold"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <Border 
                    Name="dropShadowBorder"                        
                    BorderThickness="0,0,0,1"                        
                    CornerRadius="1"
                    >
                    <Border.BorderBrush>
                        <SolidColorBrush Color="#00000000"/>
                    </Border.BorderBrush>
                    <Border Name="border"                     
                            BorderThickness="{TemplateBinding BorderThickness}"                    
                            Padding="{TemplateBinding Padding}"                     
                            CornerRadius="0"                     
                            Background="{Binding Path=Background,Mode=OneWay,RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource SolidColorBrushToGradientConverter}, ConverterParameter=0.95}"
                            >
                        <Border.BorderBrush>
                            <SolidColorBrush Color="#D8D8D8"/>
                        </Border.BorderBrush>
                        <ContentPresenter 
                            HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"                                   
                            VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                            />
                    </Border>
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="BorderBrush" TargetName="border">
                            <Setter.Value>
                                <SolidColorBrush Color="#939393"/>
                            </Setter.Value>
                        </Setter>
                        <Setter Property="BorderBrush" TargetName="dropShadowBorder">
                            <Setter.Value>
                                <SolidColorBrush Color="#EBEBEB"/>
                            </Setter.Value>
                        </Setter>
                    </Trigger>
                    <Trigger Property="IsPressed" Value="True">
                        <Setter Property="Background" Value="#4A8FF7" />
                        <Setter Property="Foreground" Value="#F5F5F5" />
                        <Setter Property="BorderBrush" TargetName="border">
                            <Setter.Value>
                                <SolidColorBrush Color="#5185D8"/>
                            </Setter.Value>
                        </Setter>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Q1: Not as far as I know

Q2: I would say styles is the way to go and you can certainly make your own class that derives from button and picks the right corner radius based on if it's Left,Middle,Right.

Q3: Should be doable with a custom value converter and your own style.

In conlusion. In this case I might have been tempted to put the background gradient and corner radius on the surrounding stackpanel. The buttons would be transparent with the text. Then you wouldn't have to deal with corner radius on individual buttons.

Edit: Added code & style for Q3 answer above. To OP; I am not sure this is exactly what you were after but perhaps there's something here that can interest you.

The way I interpreted you was that you wanted to set the button background to a certain color but it should be rendered as a linear gradient based on that color. Other posters mentioned opacity masks and that's not a bad idea at all. I thought I show how to do it using custom value converters.

The idea is that I create a custom value converted that converts a solid color brush to a linear gradient brush. Then I use this converter to convert the button background color from solid color brush to a linear gradient brush.

Here is the custom value converter:

class SolidColorBrushToGradientConverter : IValueConverter
{
    const float DefaultLowColorScale = 0.95F;

    public object Convert (object value, Type targetType, object parameter, CultureInfo culture)
    {
        var solidColorBrush = value as SolidColorBrush;

        if (!targetType.IsAssignableFrom (typeof (LinearGradientBrush)) || solidColorBrush == null)
        {
            return Binding.DoNothing;
        }

        var lowColorScale = ParseParameterAsDouble (parameter);

        var highColor = solidColorBrush.Color;
        var lowColor = Color.Multiply (highColor, lowColorScale);
        lowColor.A = highColor.A;

        return new LinearGradientBrush (
            highColor,
            lowColor,
            new Point (0, 0),
            new Point (0, 1)
            );
    }

    static float ParseParameterAsDouble (object parameter)
    {
        if (parameter is float)
        {
            return (float)parameter;
        }
        else if (parameter is string)
        {
            float result;
            return float.TryParse(
                (string) parameter, 
                NumberStyles.Float, 
                CultureInfo.InvariantCulture, 
                out result
                        )
                        ? result
                        : DefaultLowColorScale
                ;
        }
        else
        {
            return DefaultLowColorScale;
        }
    }

    public object ConvertBack (object value, Type targetType, object parameter, CultureInfo culture)
    {
        return Binding.DoNothing;
    }
}

Then I reference this in the style I copied from you (basically the same but I restructured it a bit), the important row part is this:

Background="{Binding Path=Background,Mode=OneWay,RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource SolidColorBrushToGradientConverter}, ConverterParameter=0.95}"

This means that we bind to the templated parent background (ie Button.Background), we use the converter SolidColorBrushToGradientConverter with the parameter 0.95 (this determines how much darker the "low" color should be compared to the "high" color).

The complete style:

<local:SolidColorBrushToGradientConverter x:Key="SolidColorBrushToGradientConverter" />

<Style x:Key="GoogleMiddleButton" TargetType="{x:Type Button}">
    <Setter Property="Background" Value="#F5F5F5" />
    <Setter Property="Foreground" Value="#666666"/>
    <Setter Property="FontFamily" Value="Arial"/>
    <Setter Property="FontSize" Value="13"/>
    <Setter Property="FontWeight" Value="Bold"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <Border 
                    Name="dropShadowBorder"                        
                    BorderThickness="0,0,0,1"                        
                    CornerRadius="1"
                    >
                    <Border.BorderBrush>
                        <SolidColorBrush Color="#00000000"/>
                    </Border.BorderBrush>
                    <Border Name="border"                     
                            BorderThickness="{TemplateBinding BorderThickness}"                    
                            Padding="{TemplateBinding Padding}"                     
                            CornerRadius="0"                     
                            Background="{Binding Path=Background,Mode=OneWay,RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource SolidColorBrushToGradientConverter}, ConverterParameter=0.95}"
                            >
                        <Border.BorderBrush>
                            <SolidColorBrush Color="#D8D8D8"/>
                        </Border.BorderBrush>
                        <ContentPresenter 
                            HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"                                   
                            VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                            />
                    </Border>
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="BorderBrush" TargetName="border">
                            <Setter.Value>
                                <SolidColorBrush Color="#939393"/>
                            </Setter.Value>
                        </Setter>
                        <Setter Property="BorderBrush" TargetName="dropShadowBorder">
                            <Setter.Value>
                                <SolidColorBrush Color="#EBEBEB"/>
                            </Setter.Value>
                        </Setter>
                    </Trigger>
                    <Trigger Property="IsPressed" Value="True">
                        <Setter Property="Background" Value="#4A8FF7" />
                        <Setter Property="Foreground" Value="#F5F5F5" />
                        <Setter Property="BorderBrush" TargetName="border">
                            <Setter.Value>
                                <SolidColorBrush Color="#5185D8"/>
                            </Setter.Value>
                        </Setter>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
ぇ气 2024-12-06 17:03:06

我喜欢这个挑战的样子!

Q1:其他评论/答案都是正确的,模板不能修改或继承。但是,有多种方法可以将值传递到模板中以修改其外观。一种简单(但有点hacky的方法)是使用标签在此处输入代码属性将边框CornerRadius传递到模板中。更好的方法可能是对按钮进行子类化以添加“位置”属性。

Q2:是的,您的样式/模板方向正确

Q3:修改您的模板以包含具有您所需渐变的 OpacityMask。然后,您可以将一个元素放置在该蒙版后面,或者让蒙版元素本身采用背景颜色。完整示例如下所示:

在此处输入图像描述

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
  <Window.Resources>
    <Style x:Key="GoogleButton" TargetType="{x:Type Button}">      
      <Setter Property="Background" Value="White"/>
      <Setter Property="Foreground" Value="#666666"/>
      <Setter Property="Tag">
        <Setter.Value>
          <CornerRadius>0</CornerRadius>
        </Setter.Value>
      </Setter>
      <Setter Property="FontFamily" Value="Arial"/>
      <Setter Property="FontSize" Value="13"/>
      <Setter Property="FontWeight" Value="Bold"/>
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="Button">
            <Border Name="dropShadowBorder"
                    BorderThickness="0,0,0,1"
                    CornerRadius="1"
                    BorderBrush="Transparent"
                    Background="White">
              <Grid>
                <Border Name="backgroundFill" 
                        BorderBrush="Red"
                        Background="{TemplateBinding Background}"
                        CornerRadius="{TemplateBinding Tag}">
                  <Border.OpacityMask>
                    <LinearGradientBrush StartPoint="0,1" EndPoint="0,0">
                      <GradientStop Color="#FF000000" Offset="0"/>
                      <GradientStop Color="#00000000" Offset="1"/>
                    </LinearGradientBrush>
                  </Border.OpacityMask>
                </Border>
                <Border Name="border" 
                    BorderThickness="{TemplateBinding BorderThickness}"
                    Padding="{TemplateBinding Padding}" 
                    CornerRadius="{TemplateBinding Tag}" 
                    Background="Transparent">
                  <Border.BorderBrush>
                    <SolidColorBrush Color="#D8D8D8"/>
                  </Border.BorderBrush>
                  <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
                                  VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                </Border>
              </Grid>
            </Border>            
            <ControlTemplate.Triggers>
              <Trigger Property="IsMouseOver" Value="True">
                <Setter Property="BorderBrush" TargetName="border">
                  <Setter.Value>
                    <SolidColorBrush Color="#939393"/>
                  </Setter.Value>
                </Setter>
                <Setter Property="BorderBrush" TargetName="dropShadowBorder">
                  <Setter.Value>
                    <SolidColorBrush Color="#EBEBEB"/>
                  </Setter.Value>
                </Setter>
              </Trigger>
            </ControlTemplate.Triggers>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
      <Style.Triggers>
        <Trigger Property="IsMouseOver" Value="True">
          <Setter Property="Foreground" Value="#333333"/>
        </Trigger>
        <Trigger Property="IsPressed" Value="True">
          <Setter Property="Background">
            <Setter.Value>
              <LinearGradientBrush StartPoint="0,1" EndPoint="0,0">
                <GradientStop Color="#F1F1F1" Offset="1"/>
                <GradientStop Color="#F5F5F5" Offset="0"/>
              </LinearGradientBrush>
            </Setter.Value>
          </Setter>
        </Trigger>
      </Style.Triggers>
    </Style>
  </Window.Resources>
  <Grid>
    <StackPanel Orientation="Horizontal"
                VerticalAlignment="Top">
      <Button Style="{StaticResource GoogleButton}" Content="Archive">
        <Button.Tag>
          <CornerRadius>2,0,0,2</CornerRadius>
        </Button.Tag>
      </Button>
      <Button Style="{StaticResource GoogleButton}" Content="Spam"
              Background="LightBlue"/>
      <Button Style="{StaticResource GoogleButton}" Content="Delete">
        <Button.Tag>
          <CornerRadius>0,2,2,0</CornerRadius>
        </Button.Tag>
      </Button>
    </StackPanel>
  </Grid>
</Window>

I like the look of this challenge!

Q1: The other comments / answers are correct, templates cannot be modified or inherited. However, there are ways of passing values into your template in order to modify their appearance. A simple (yet slightly hacky way) would be to pass the border CornerRadius into the template using the Tag enter code hereproperty. A better way might be to subclass button to add a 'location' property.

Q2: Yes, you are on the right track with styles / templates

Q3: Modify your template to include an OpacityMask that has the gradient you desire. You can then either place an element behind this mask or have the masked element take the background colour itself. Complete example shown below:

enter image description here

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
  <Window.Resources>
    <Style x:Key="GoogleButton" TargetType="{x:Type Button}">      
      <Setter Property="Background" Value="White"/>
      <Setter Property="Foreground" Value="#666666"/>
      <Setter Property="Tag">
        <Setter.Value>
          <CornerRadius>0</CornerRadius>
        </Setter.Value>
      </Setter>
      <Setter Property="FontFamily" Value="Arial"/>
      <Setter Property="FontSize" Value="13"/>
      <Setter Property="FontWeight" Value="Bold"/>
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="Button">
            <Border Name="dropShadowBorder"
                    BorderThickness="0,0,0,1"
                    CornerRadius="1"
                    BorderBrush="Transparent"
                    Background="White">
              <Grid>
                <Border Name="backgroundFill" 
                        BorderBrush="Red"
                        Background="{TemplateBinding Background}"
                        CornerRadius="{TemplateBinding Tag}">
                  <Border.OpacityMask>
                    <LinearGradientBrush StartPoint="0,1" EndPoint="0,0">
                      <GradientStop Color="#FF000000" Offset="0"/>
                      <GradientStop Color="#00000000" Offset="1"/>
                    </LinearGradientBrush>
                  </Border.OpacityMask>
                </Border>
                <Border Name="border" 
                    BorderThickness="{TemplateBinding BorderThickness}"
                    Padding="{TemplateBinding Padding}" 
                    CornerRadius="{TemplateBinding Tag}" 
                    Background="Transparent">
                  <Border.BorderBrush>
                    <SolidColorBrush Color="#D8D8D8"/>
                  </Border.BorderBrush>
                  <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
                                  VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                </Border>
              </Grid>
            </Border>            
            <ControlTemplate.Triggers>
              <Trigger Property="IsMouseOver" Value="True">
                <Setter Property="BorderBrush" TargetName="border">
                  <Setter.Value>
                    <SolidColorBrush Color="#939393"/>
                  </Setter.Value>
                </Setter>
                <Setter Property="BorderBrush" TargetName="dropShadowBorder">
                  <Setter.Value>
                    <SolidColorBrush Color="#EBEBEB"/>
                  </Setter.Value>
                </Setter>
              </Trigger>
            </ControlTemplate.Triggers>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
      <Style.Triggers>
        <Trigger Property="IsMouseOver" Value="True">
          <Setter Property="Foreground" Value="#333333"/>
        </Trigger>
        <Trigger Property="IsPressed" Value="True">
          <Setter Property="Background">
            <Setter.Value>
              <LinearGradientBrush StartPoint="0,1" EndPoint="0,0">
                <GradientStop Color="#F1F1F1" Offset="1"/>
                <GradientStop Color="#F5F5F5" Offset="0"/>
              </LinearGradientBrush>
            </Setter.Value>
          </Setter>
        </Trigger>
      </Style.Triggers>
    </Style>
  </Window.Resources>
  <Grid>
    <StackPanel Orientation="Horizontal"
                VerticalAlignment="Top">
      <Button Style="{StaticResource GoogleButton}" Content="Archive">
        <Button.Tag>
          <CornerRadius>2,0,0,2</CornerRadius>
        </Button.Tag>
      </Button>
      <Button Style="{StaticResource GoogleButton}" Content="Spam"
              Background="LightBlue"/>
      <Button Style="{StaticResource GoogleButton}" Content="Delete">
        <Button.Tag>
          <CornerRadius>0,2,2,0</CornerRadius>
        </Button.Tag>
      </Button>
    </StackPanel>
  </Grid>
</Window>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文