• 15、wpf之button样式小记


    前言:Button算是开发中用到的比较多的控件了,最开始使用原生的样式,长方形的样子,然后设置下Button的Content属性。随着学习的深入,需要去设置下Button的背景色,再往后就需要改下Button的模板来满足更高的需求设计。

    一、简介

    可以看到,Button继承至ContentControl控件, Button有个Content属性而这个Content可以是多种控件形式,查看Button的模板可以看到,用来承载这个内容的是一个ContentPresenter控件。

    通过官网可以看到这个ContentPresenter类的继承关系 

    二、Background

    简单的如下

    <Button Background="AliceBlue"/>

    可以看到,这个Background属性类型是Brush,因此我们可以通过应用不同的Brush来改变Button的Background,从而使Background更加丰富。

    官网中对Brush的注解,Brush有多个继承者,都可以用

    2.1  LinearGradientBrush

    1. <Button Width="60" Height="60">
    2. <Button.Background>
    3. <LinearGradientBrush EndPoint="0.851,0.838" StartPoint="0.115,0.169">
    4. <GradientStop Color="#FFA21212" Offset="0"/>
    5. <GradientStop Color="#FFF8C906" Offset="1"/>
    6. </LinearGradientBrush>
    7. </Button.Background>
    8. </Button>

    2.2 RadialGradientBrush

    1. <Button Width="60" Height="60">
    2. <Button.Background>
    3. <RadialGradientBrush>
    4. <GradientStop Color="#FFA21212" Offset="1"/>
    5. <GradientStop Color="#FFF8C906" Offset="0"/>
    6. </RadialGradientBrush>
    7. </Button.Background>
    8. </Button>

    2.3 ImageBrush 

    1. <Button Width="60" Height="60">
    2. <Button.Background>
    3. <ImageBrush ImageSource="/项目.png"/>
    4. </Button.Background>
    5. </Button>

    2.4 DrawingBrush 

    1. <Button Width="60" Height="60">
    2. <Button.Background>
    3. <DrawingBrush Viewport="0,0,0.5,0.5" TileMode="Tile">
    4. <DrawingBrush.Drawing>
    5. <GeometryDrawing Brush="Red">
    6. <GeometryDrawing.Geometry>
    7. <GeometryGroup>
    8. <EllipseGeometry RadiusX="20" RadiusY="45" Center="50,50" />
    9. <EllipseGeometry RadiusX="45" RadiusY="20" Center="50,50" />
    10. </GeometryGroup>
    11. </GeometryDrawing.Geometry>
    12. <GeometryDrawing.Pen>
    13. <Pen Thickness="10">
    14. <Pen.Brush>
    15. <LinearGradientBrush>
    16. <GradientStop Offset="0.0" Color="Black" />
    17. <GradientStop Offset="1.0" Color="Gray" />
    18. </LinearGradientBrush>
    19. </Pen.Brush>
    20. </Pen>
    21. </GeometryDrawing.Pen>
    22. </GeometryDrawing>
    23. </DrawingBrush.Drawing>
    24. </DrawingBrush>
    25. </Button.Background>
    26. </Button>

    2.5 VisualBrush

    1. <Button Width="60" Height="60">
    2. <Button.Background>
    3. <VisualBrush>
    4. <VisualBrush.Visual>
    5. <StackPanel Background="White">
    6. <Rectangle Width="25" Height="25" Fill="Orange" Margin="6" />
    7. <TextBlock FontSize="10pt" Margin="2">BrawDraw</TextBlock>
    8. <Button Margin="10">Button</Button>
    9. </StackPanel>
    10. </VisualBrush.Visual>
    11. </VisualBrush>
    12. </Button.Background>
    13. </Button>

    二、Content

    2.1 字符串

    1. <!--Create a Button with a string as its content.-->
    2. <Button Content="1111111111" Height="60" Width="60"/>
    3. <Button>This is string content of a Button</Button>

    2.2  DateTime object

    1. <!--Create a Button with a DateTime object as its content.-->
    2. <Button xmlns:sys="clr-namespace:System;assembly=mscorlib">
    3. <sys:DateTime>2004/3/4 13:6:55</sys:DateTime>
    4. </Button>

    2.3 UIElement

    1. <!--Create a Button with a single UIElement as its content.-->
    2. <Button>
    3. <Rectangle Height="40" Width="40" Fill="Blue"/>
    4. </Button>

    2.4 panel

    1. <!--Create a Button with a panel that contains multiple objects
    2. as its content.-->
    3. <Button>
    4. <StackPanel>
    5. <Ellipse Height="40" Width="40" Fill="Blue"/>
    6. <TextBlock TextAlignment="Center">Button</TextBlock>
    7. </StackPanel>
    8. </Button>

    2.5 说明

    Because the Content property is of type Object, there are no restrictions on what you can put in a ContentControl. The Content is displayed by a ContentPresenter, which is in the ControlTemplate of the ContentControl. Every ContentControl type in WPF has a ContentPresenter in its default ControlTemplate

    由于Content属性的类型是Object,因此对可以放入的内容ContentControl没有限制。该Content属性通过ContentPresenter显示,而这个ContentPresenter存在于ContentControl的ControlTemplate属性中。WPF中的每一个ContentControl类型控件都有一个ContentPresenter属性,默认存在ControlTemplate中。

    三、外观

    The ContentPresenter uses the following logic to display the Content (ContentPresenter就是用来显示Content的,下面是显示逻辑):

    3.1 原生样式

    1. <Style x:Key="ButtonStyle2" TargetType="{x:Type Button}">
    2. <Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual1}"/>
    3. <Setter Property="Background" Value="{StaticResource Button.Static.Background1}"/>
    4. <Setter Property="BorderBrush" Value="{StaticResource Button.Static.Border1}"/>
    5. <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
    6. <Setter Property="BorderThickness" Value="1"/>
    7. <Setter Property="HorizontalContentAlignment" Value="Center"/>
    8. <Setter Property="VerticalContentAlignment" Value="Center"/>
    9. <Setter Property="Padding" Value="1"/>
    10. <Setter Property="Template">
    11. <Setter.Value>
    12. <ControlTemplate TargetType="{x:Type Button}">
    13. <Border x:Name="border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" SnapsToDevicePixels="true">
    14. <ContentPresenter x:Name="contentPresenter" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
    15. </Border>
    16. <ControlTemplate.Triggers>
    17. <Trigger Property="IsDefaulted" Value="true">
    18. <Setter Property="BorderBrush" TargetName="border" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
    19. </Trigger>
    20. <Trigger Property="IsMouseOver" Value="true">
    21. <Setter Property="Background" TargetName="border" Value="{StaticResource Button.MouseOver.Background1}"/>
    22. <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.MouseOver.Border1}"/>
    23. </Trigger>
    24. <Trigger Property="IsPressed" Value="true">
    25. <Setter Property="Background" TargetName="border" Value="{StaticResource Button.Pressed.Background1}"/>
    26. <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.Pressed.Border1}"/>
    27. </Trigger>
    28. <Trigger Property="IsEnabled" Value="false">
    29. <Setter Property="Background" TargetName="border" Value="{StaticResource Button.Disabled.Background1}"/>
    30. <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.Disabled.Border1}"/>
    31. <Setter Property="TextElement.Foreground" TargetName="contentPresenter" Value="{StaticResource Button.Disabled.Foreground1}"/>
    32. </Trigger>
    33. </ControlTemplate.Triggers>
    34. </ControlTemplate>
    35. </Setter.Value>
    36. </Setter>
    37. </Style>

    有关外观的设计就在ControlTemplate属性上,这个原生的没做什么改变,如果设置Content为string,就会像上面最后一条一样,Content调用ToString去转换并创建个TextBlock去承载这个转换后的string。

    3.2 UIElement

    使用image作为Content的元素,上面第四条所说的。

    1. <Button Height="60" Width="60">
    2. <Image Source="/项目.png"/>
    3. </Button>

    3.2 修改ControlTemplate

    原生的样式,边框很明显,这时就需要修改下ControlTemplate了

    1. <Style x:Key="ButtonStyle1" TargetType="{x:Type Button}">
    2. <Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual}"/>
    3. <Setter Property="Background" Value="{StaticResource Button.Static.Background}"/>
    4. <Setter Property="BorderBrush" Value="{StaticResource Button.Static.Border}"/>
    5. <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
    6. <Setter Property="BorderThickness" Value="1"/>
    7. <Setter Property="HorizontalContentAlignment" Value="Center"/>
    8. <Setter Property="VerticalContentAlignment" Value="Center"/>
    9. <Setter Property="Padding" Value="1"/>
    10. <Setter Property="Template">
    11. <Setter.Value>
    12. <ControlTemplate TargetType="{x:Type Button}">
    13. <Grid>
    14. <Grid.RowDefinitions>
    15. <RowDefinition Height="0"/>
    16. <RowDefinition Height="*"/>
    17. </Grid.RowDefinitions>
    18. <Image Source="/Resource/send.png" Margin="0 10 0 0"/>
    19. <Border x:Name="border" BorderThickness="1" SnapsToDevicePixels="true" Grid.Row="1">
    20. <ContentPresenter x:Name="contentPresenter" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
    21. </Border>
    22. </Grid>
    23. <ControlTemplate.Triggers>
    24. <Trigger Property="IsDefaulted" Value="true">
    25. <Setter Property="BorderBrush" TargetName="border" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
    26. </Trigger>
    27. <Trigger Property="IsMouseOver" Value="true">
    28. <Setter Property="Background" TargetName="border" Value="{StaticResource Button.MouseOver.Background}"/>
    29. <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.MouseOver.Border}"/>
    30. </Trigger>
    31. <Trigger Property="IsPressed" Value="true">
    32. <Setter Property="Background" TargetName="border" Value="{StaticResource Button.Pressed.Background}"/>
    33. <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.Pressed.Border}"/>
    34. </Trigger>
    35. <Trigger Property="IsEnabled" Value="false">
    36. <Setter Property="Background" TargetName="border" Value="{StaticResource Button.Disabled.Background}"/>
    37. <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.Disabled.Border}"/>
    38. <Setter Property="TextElement.Foreground" TargetName="contentPresenter" Value="{StaticResource Button.Disabled.Foreground}"/>
    39. </Trigger>
    40. </ControlTemplate.Triggers>
    41. </ControlTemplate>
    42. </Setter.Value>
    43. </Setter>
    44. </Style>

     我们把ControlTemplate摘出来看看,原样式中使用一个Border包裹一个ContentPrensenter。

    修改后使用了Grid作为ContentPresenter的父容器。其实这里分了两层,一层高度是0,其实就一层。

    这里还有个问题,就是鼠标移动上去后,会有个背景,不好看

    这个背景是在 ControlTemplate.Triggers中设置的,设置的属性是IsMouseOver。想去掉这个背景,暴力点的做法直接注释掉那段代码。

    3.3 升级

    鼠标移上去会放大这个Content,笔者代码中Content设置为Image类型的。

    1. <Style x:Key="ButtonStyle" TargetType="{x:Type Button}">
    2. <Setter Property="VerticalAlignment" Value="Center"/>
    3. <Setter Property="HorizontalAlignment" Value="Center"/>
    4. <Setter Property="VerticalContentAlignment" Value="Center"/>
    5. <Setter Property="HorizontalContentAlignment" Value="Center"/>
    6. <Setter Property="Template">
    7. <Setter.Value>
    8. <ControlTemplate TargetType="{x:Type Button}">
    9. <ControlTemplate.Resources>
    10. <Storyboard x:Key="Storyboard1">
    11. <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)" Storyboard.TargetName="grid">
    12. <SplineDoubleKeyFrame KeyTime="0:0:0.5" Value="1.25"/>
    13. </DoubleAnimationUsingKeyFrames>
    14. <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)" Storyboard.TargetName="grid">
    15. <SplineDoubleKeyFrame KeyTime="0:0:0.5" Value="1.25"/>
    16. </DoubleAnimationUsingKeyFrames>
    17. </Storyboard>
    18. <Storyboard x:Key="Storyboard2">
    19. <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)" Storyboard.TargetName="grid">
    20. <SplineDoubleKeyFrame KeyTime="0:0:0.5" Value="1"/>
    21. </DoubleAnimationUsingKeyFrames>
    22. <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)" Storyboard.TargetName="grid">
    23. <SplineDoubleKeyFrame KeyTime="0:0:0.5" Value="1"/>
    24. </DoubleAnimationUsingKeyFrames>
    25. </Storyboard>
    26. </ControlTemplate.Resources>
    27. <Grid x:Name="grid" RenderTransformOrigin="0.5,0.5">
    28. <Grid.RenderTransform>
    29. <TransformGroup>
    30. <ScaleTransform/>
    31. <SkewTransform/>
    32. <RotateTransform/>
    33. <TranslateTransform/>
    34. </TransformGroup>
    35. </Grid.RenderTransform>
    36. <Label Name="lbl" Content="{TemplateBinding Content}" Background="Transparent" Height="{TemplateBinding Height}"
    37. Width="{TemplateBinding Width}" VerticalAlignment="Center" HorizontalAlignment="Center"/>
    38. </Grid>
    39. <ControlTemplate.Triggers>
    40. <Trigger Property="IsFocused" Value="True"/>
    41. <Trigger Property="IsDefaulted" Value="True"/>
    42. <Trigger Property="IsMouseOver" Value="True">
    43. <!--<Setter Property="Background" TargetName="lbl" Value="red"/>-->
    44. <Trigger.ExitActions>
    45. <BeginStoryboard x:Name="Storyboard_Copy1_BeginStoryboard" Storyboard="{StaticResource Storyboard2}"/>
    46. </Trigger.ExitActions>
    47. <Trigger.EnterActions>
    48. <BeginStoryboard Storyboard="{StaticResource Storyboard1}"/>
    49. </Trigger.EnterActions>
    50. </Trigger>
    51. <Trigger Property="IsPressed" Value="True">
    52. <Setter Property="Background" TargetName="lbl" Value="#000000FF"/>
    53. </Trigger>
    54. <Trigger Property="IsEnabled" Value="False"/>
    55. </ControlTemplate.Triggers>
    56. </ControlTemplate>
    57. </Setter.Value>
    58. </Setter>
    59. </Style>

    加了个动画,然后在 IsMouseOver事件中进行操作。

    四、引用文献

    4.1 Button 类 (System.Windows.Controls) | Microsoft Docs

    4.2 ContentPresenter 类 (System.Windows.Controls) | Microsoft Docs

    4.3 Brush 类 (System.Windows.Media) | Microsoft Docs

    4.4 简述WPF中的画刷(Brush)_Andrewniu的博客-CSDN博客_brush wpf

    4.5 ContentControl.Content 属性 (System.Windows.Controls) | Microsoft Docs

  • 相关阅读:
    A-Level化学例题解析及练习Co-ordinate bond
    Java 内存模型(JMM)
    构建SpringBoot项目时报错 SocketTimeoutException connect timed out
    Android hook方式抓包
    原型模式-Prototype Pattern
    开源项目datavines内存泄漏问题分析
    docker配置nginx,并部署多个项目
    k8s使用ECK(2.4)形式部署elasticsearch+kibana-http协议
    1.5-39:与7无关的数
    13-Error接口错误处理以及go Module
  • 原文地址:https://blog.csdn.net/roujian0985/article/details/125257144