WPF桌面端开发-Button的使用及样式自定义

前言

在WPF(Windows Presentation Foundation)中设置按钮(Button)涉及到多种属性和功能。

以下是一些常见的设置方法和示例:

设置按钮文本和点击事件

1
<Button Content="Click Me" Click="ButtonClickHandler" />

其中,Content属性用于设置按钮的文本显示,“Click Me”是按钮显示的文本内容。

Click属性是按钮的点击事件,ButtonClickHandler是处理点击事件的方法名。

设置按钮样式和外观

WPF允许通过样式(Style)来自定义按钮的外观。例如,可以在应用程序的资源文件中定义按钮样式:

1
2
3
4
5
6
7
8
9
10
11
<Window.Resources>
<Style TargetType="Button" x:Key="CustomButtonStyle">
<Setter Property="Background" Value="LightBlue"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="FontFamily" Value="Arial"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="Padding" Value="10"/>
</Style>
</Window.Resources>

<Button Content="Styled Button" Style="{StaticResource CustomButtonStyle}" Click="ButtonClickHandler" />

定义了一个名为CustomButtonStyle的样式,设置了按钮的背景、前景(文本颜色)、字体等属性。然后,通过Style属性将这个样式应用到按钮上。

设置按钮图标

可以通过WPF的Content属性来设置按钮的内容,这不仅限于文本,还可以是其他元素,比如图标。

1
2
3
4
5
6
<Button Click="ButtonClickHandler">
<StackPanel Orientation="Horizontal">
<Image Source="/Images/icon.png" Width="20" Height="20"/>
<TextBlock Margin="5,0,0,0" Text="Button with Icon"/>
</StackPanel>
</Button>

在这个示例中,按钮的内容是一个StackPanel,包含一个图像和一个文本块,从而实现了带图标的按钮。

动态设置按钮属性

除了静态设置外,还可以在代码中动态设置按钮的属性。

例如,在代码中修改按钮的文本或样式:

1
2
3
4
5
6
7
// 在代码中修改按钮文本
myButton.Content = "New Text";

// 在代码中修改按钮样式
Style newStyle = new Style(typeof(Button));
newStyle.Setters.Add(new Setter(Button.BackgroundProperty, Brushes.Green));
myButton.Style = newStyle;

组件内设置

1
2
3
4
5
6
7
8
9
10
11
12
<Button>
<Button.Style>
<Style TargetType="Button">
<Setter Property="Foreground" Value="White" />
<Style.Triggers>
<DataTrigger Binding="{Binding Selected}" Value="true">
<Setter Property="Foreground" Value="#ffffff" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>

样式触发器和模板触发器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<Style x:Key="ExitBtn" TargetType="Button">
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Background" Value="#F0F6FC" />
<Setter Property="Foreground" Value="#253A70" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border
Width="75"
Height="88"
Background="{TemplateBinding Background}">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<Image
x:Name="MImg"
Width="30"
Margin="0,10,0,0"
HorizontalAlignment="Center"
Source="/Images/Blackboard2/class_7un.png" />
<TextBlock
Margin="0,8,0,8"
HorizontalAlignment="Center"
FontSize="16"
Foreground="{TemplateBinding Foreground}"
Text="退出" />
</StackPanel>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="MImg" Property="Source" Value="/Images/Blackboard2/class_7s.png" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#339DFF" />
<Setter Property="Foreground" Value="White" />
</Trigger>
</Style.Triggers>
</Style>

注意

Style.Triggers 不能修改自定义模板中的属性。

ControlTemplate.Triggers是可以改模板的属性。

自定义Button

/Resources/StyleButton.xaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="MyButton" TargetType="{x:Type Button}">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="Background" Value="#2D8CF0" />
<Setter Property="Foreground" Value="#ffffff" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border
Name="border"
Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
ClipToBounds="True"
CornerRadius="4">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Opacity" Value="0.8" />
</Trigger>

<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" Value="0.6" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

自定义圆角Button

Button实现圆角很简单只需Button ContentTemplate修改样式模板就可以实现了。

但是这样无法达到复用,比如另一个按钮设计的不需要圆角样式又用的同一套怎么办?

当然可以在把样式复制下然后改一个样式名字修改下样式就可以了。

但是这样两份样式几乎一样,只不过一个圆角一个不是。

所以我们可以通过自定义Button控件给Button新增一个依赖属性完成这个功能。

添加属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
using System.Windows;
using System.Windows.Controls;

namespace ColorPicker.Views
{
internal class ZRoundButton : Button
{
#region 属性
public static readonly DependencyProperty BorderRadiusProperty = DependencyProperty.Register("BorderRadius", typeof(int), typeof(ZRoundButton), new FrameworkPropertyMetadata());

public int BorderRadius
{
get { return (int)GetValue(BorderRadiusProperty); }
set { SetValue(BorderRadiusProperty, value); }
}
#endregion 属性
}
}

定义样式

/Resources/StyleZRoundButton.xaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SchoolClient.Views">
<Style x:Key="ZRoundButtonStyle" TargetType="{x:Type local:ZRoundButton}">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border
Name="border"
Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{Binding Path=BorderRadius, RelativeSource={RelativeSource TemplatedParent}}">
<ContentPresenter
Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Opacity" Value="0.8" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

全局引用

Application中添加引用

1
2
3
4
5
6
7
8
9
<Application
x:Class="SchoolClient.MyApp"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Wins/Welcome.xaml">
<Application.Resources>
<ResourceDictionary Source="pack://application:,,,/Resources/OverwrideDefaultControlStyles.xaml" />
</Application.Resources>
</Application>

使用

定义好这个属性就可以在控件中使用了

1
2
3
4
5
6
7
8
9
10
<view:ZRoundButton
BorderRadius="23"
Width="300"
Height="46"
HorizontalAlignment="Center"
Background="#4597FF"
Content="关闭"
Cursor="Hand"
FontSize="20"
Foreground="White"/>

其中主要是BorderRadius="5"用来调整圆角。

我们再看看以前要实现就需要以下的代码,是不是感觉比以前简便多了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<Button
Width="300"
Height="46"
Content="关闭"
Cursor="Hand"
FontSize="20"
Foreground="White">
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Border
BorderBrush="{TemplateBinding Control.BorderBrush}"
BorderThickness="0"
CornerRadius="23">
<Border.Background>#4597FF</Border.Background>
<ContentPresenter
HorizontalAlignment="Center"
VerticalAlignment="Center"
Content="{TemplateBinding ContentControl.Content}" />
</Border>
</ControlTemplate>
</Button.Template>
</Button>

事件

单击事件

1
2
3
4
<Button
Background="Transparent"
Click="AnsItemClick"
Tag="{Binding}" />

代码

1
2
3
4
private void AnsItemClick(object sender, RoutedEventArgs e)
{
Console.WriteLine(@"单击事件");
}

双击事件

方式1

XAML:

1
<Button Content="Click Me" MouseDoubleClick="Button_MouseDoubleClick"/>

C#:

1
2
3
4
5
private void Button_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
// 双击事件的处理逻辑
MessageBox.Show("Double clicked!");
}

注意

这样双击事件触发的时候,同时也触发了两次单击事件。

方式2

WPF提供了一专门处理双击事件的事件类型,即PreviewMouseDoubleClick。

这个事件会在双击时触发,可以在这里处理双击事件逻辑,并避免触发单击事件。

XAML部分:

1
<Button Content="双击我" PreviewMouseDoubleClick="Button_PreviewMouseDoubleClick" />

代码部分:

1
2
3
4
5
6
7
8
private void Button_PreviewMouseDoubleClick(object sender, MouseButtonEventArgs e)
{
// 双击事件逻辑处理
MessageBox.Show("双击事件发生了!");

// 阻止单击事件继续传播
e.Handled = true;
}

当双击按钮时,会触发Button_PreviewMouseDoubleClick方法。

在方法中,处理双击事件的逻辑并设置e.Handled = true可以防止单击事件继续传播。

注意

这样只能避免第二次的点击事件不触发单击事件,双击中的第一次依旧会触发单击事件。

方式3

1
2
3
4
<Button
Background="Transparent"
PreviewMouseDown="AnsItemDbClick"
Tag="{Binding}" />

代码

1
2
3
4
5
6
7
8
9
10
11
12
private void AnsItemDbClick(object sender, MouseButtonEventArgs e)
{
if (e.ClickCount > 1)
{
Console.WriteLine(@"双击事件");
e.Handled = true;
}
else
{
Console.WriteLine(@"单击事件");
}
}

注意

这样只能避免第二次的点击事件不触发单击事件,双击中的第一次依旧会触发单击事件。

双击不触发点击事件

如果我们想触发双击事件的时候,不触发单击事件,我们只能延迟执行我们的单击事件。

1
2
<Button Content="Click Me"
PreviewMouseDown="Button_PreviewMouseDown"/>

当点击下的时候设置一个延迟执行的定时任务,如果任务还没触发的时候,双击了,取消之前的定时任务,不过这样单击任务都会延迟执行,体验不是很好。

目前没有别的方式。