WPF样式/模板继承

Jon*_*lis 6 c# wpf user-interface styles controltemplates

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

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

新的GMail按钮

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

右侧和左侧按钮非常相似,但只有2个不同.它们的左侧或右侧的圆角半径为1,边距为15,而中间的按钮则将它们都设置为0.

问题!

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

Q2.样式是在WPF中解决此问题的正确方法.在WinForms中,您将创建一个自定义控件,该控件具有链接到枚举的可见属性,即您单击按钮,样式选项可能是Left,Middle,Right.

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

即按钮如下方的蓝色按钮和灰色/普通按钮

谷歌按钮2

我的风格

<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>
Run Code Online (Sandbox Code Playgroud)

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

Ken*_*art 8

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

<Style TargetType="Button">
    <Setter Property="local:ExtendedProperties.CornerRadius" Value="0"/>
    ...
Run Code Online (Sandbox Code Playgroud)

并在模板中使用它:

<Border CornerRadius="{Binding Path=(local:ExtendedProperties.CornerRadius), RelativeSource={RelativeSource TemplatedParent}">
Run Code Online (Sandbox Code Playgroud)

然后我可以在本地覆盖它,就像我覆盖任何其他属性一样:

<Button Content="Archive" local:ExtendedProperties.CornerRadius="5,0,0,5"/>
<Button Content="Span"/>
<Button Content="Delete" local:ExtendedProperties.CornerRadius="0,5,5,0"/>
Run Code Online (Sandbox Code Playgroud)

就我而言,这给了我(显然,我的主题是黑暗的):

在此输入图像描述

只是通过调整我的几个主题的附加属性,我创建了这个效果:

在此输入图像描述

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

缺点是它是附属物,因此更难发现.记录您的主题将有助于这方面.

那么,回答你的具体问题:

Q1.是的,请参阅上面的答案.您可以在本地覆盖或定义覆盖该属性的新样式.

Q2.这是一个灰色地带.在我看来,如果它纯粹是视觉(不是行为),那么风格就是你要走的路.当然,如果失控,您可能希望继承所有内置控件并添加您的特定属性.但这会使您的主题更难以重复使用,并且您的应用程序更难以开发(因为您需要使用您的控件集而不是标准控件集).

Q3.我说它可以在代码中使用,但不能直观地用作控件使用者.我认为你最好定义额外的附加属性 - 例如.ExtendedProperties.HoverBackground,ExtendedProperties.PressedBackground- 以完全相同的方式使用模板中的那些.然后,当您的控件处于各种状态时,您的控件的使用者可以更好地控制所使用的画笔.我以前做过这个,但是使用了更多的通用属性名称(SecondaryBackground,TernaryBackground),所以我可以在其他上下文中重用这些属性.再次,记录您的主题是有帮助的.