文章目录
- 1、案例效果
- 1、按钮分类
- 2、E类按钮功能实现与封装
- 1.文件创建与代码实现
- 2、样式引用与封装
- 3、F类按钮功能实现与封装
- 1、文件创建与代码实现
- 2、样式引用与封装
- 3、按钮案例演示
- 1、页面实现与文件创建
- 2、运行效果如下
- 4、源代码获取
1、案例效果
1、按钮分类
在WPF开发中,最常见的就是按钮的使用,这里我们总结以下大概的按钮种类,然后分别实现对应的按钮。
A【纯文字按钮】 只有文字,但是会根据根据操作改变颜色
B【纯图片按钮 】只有图片,但是会有图片旋转或者变色特效
C【文字图片按钮】图片在左,文字在右边,有部分特效
D【文字图片按钮】图片在右,文字在左边,有部分特效
E【文字图片按钮】图片在上,文字在下,有部分特效
F【文字图片按钮】图片在下,文字在上,有部分特效
2、E类按钮功能实现与封装
1.文件创建与代码实现
打开 Wpf_Examples 项目,在自定义按钮类库中创建 ImageTextButton.cs 文件 和 ImageTextButton.xaml 资源样式文件。完成后如下图所示:
ImageTextButton.cs 代码如下所示:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace CustomControlLib.Buttons
{
public class ImageTextButton : Button
{
public static readonly DependencyProperty ImageSourceProperty =
DependencyProperty.Register("ImageSource", typeof(ImageSource), typeof(ImageTextButton));
public ImageSource ImageSource
{
get => (ImageSource)GetValue(ImageSourceProperty);
set => SetValue(ImageSourceProperty, value);
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(ImageTextButton));
public string Text
{
get => (string)GetValue(TextProperty);
set => SetValue(TextProperty, value);
}
public static readonly DependencyProperty IsDashedBorderProperty =
DependencyProperty.Register("IsDashedBorder", typeof(bool), typeof(ImageTextButton), new PropertyMetadata(false, OnIsDashedBorderChanged));
public bool IsDashedBorder
{
get => (bool)GetValue(IsDashedBorderProperty);
set => SetValue(IsDashedBorderProperty, value);
}
private static void OnIsDashedBorderChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((ImageTextButton)d).InvalidateVisual();
}
public ImageTextButton()
{
DefaultStyleKey = typeof(ImageTextButton);
}
}
}
ImageTextButton.xaml 样式代码如下:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CustomControlLib.Buttons">
<Style TargetType="{x:Type local:ImageTextButton}">
<Setter Property="Width" Value="60"/>
<Setter Property="Height" Value="60"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:ImageTextButton}">
<Border x:Name="Border"
BorderBrush="Gray"
BorderThickness="1"
CornerRadius="8"
Background="Transparent"
SnapsToDevicePixels="true" Opacity="1" Width="{TemplateBinding Width}" Height="{TemplateBinding Height}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="65*"/>
<RowDefinition Height="35*"/>
</Grid.RowDefinitions>
<Image x:Name="Image" Grid.Row="0"
Source="{TemplateBinding ImageSource}"
HorizontalAlignment="Center"
VerticalAlignment="Center" Margin="0 5 0 0" Opacity="1"/>
<TextBlock x:Name="TextBlock" Grid.Row="1"
Text="{TemplateBinding Text}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="14"
Foreground="Black" Opacity="1"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="LightGray" TargetName="Border"/>
<Setter Property="BorderThickness" Value="0" TargetName="Border"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="DarkGray" TargetName="Border"/>
</Trigger>
<Trigger Property="IsEnabled" Value="True">
<Setter Property="Background" Value="DarkGray" TargetName="Border"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="Gray"/>
<Setter Property="Background" Value="LightGray" TargetName="Border"/>
</Trigger>
<Trigger Property="IsDashedBorder" Value="True">
<Setter Property="IsEnabled" Value="false"/>
<Setter Property="Opacity" Value="0.6" TargetName="Border"/>
<Setter Property="Opacity" Value="0.6" TargetName="Image"/>
<Setter Property="Opacity" Value="0.6" TargetName="TextBlock"/>
<Setter Property="Foreground" Value="Gray"/>
<Setter Property="BorderBrush" TargetName="Border">
<Setter.Value>
<VisualBrush Stretch="Fill" TileMode="Tile">
<VisualBrush.Visual>
<Rectangle StrokeDashArray="2 1" Stroke="Gray" StrokeThickness="1" Width="50" Height="50"/>
</VisualBrush.Visual>
</VisualBrush>
</Setter.Value>
</Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
2、样式引用与封装
完成按钮样式后,只需要在 Generic.xaml 文件中引用 按钮样式即完成整个按钮的封装了,这样只要项目引用 自定义按钮库即可使用该自定义按钮了。
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/CustomControlLib;component/Themes/Buttons/IconFontButton.xaml" />
<ResourceDictionary Source="pack://application:,,,/CustomControlLib;component/Themes/Buttons/FontIconButton.xaml" />
<ResourceDictionary Source="pack://application:,,,/CustomControlLib;component/Themes/Buttons/ImageTextButton.xaml" />
</ResourceDictionary.MergedDictionaries>
3、F类按钮功能实现与封装
1、文件创建与代码实现
F类功能按钮其实就是E类按钮样式中图片与文本的交换,和CD类似。
在自定义控件库中新建 TextImageButton.cs 和样式文件 TextImageButton.xaml 。如下所示:
TextImageButton.cs 代码如下所示:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace CustomControlLib.Buttons
{
public class TextImageButton : Button
{
public static readonly DependencyProperty ImageSourceProperty =
DependencyProperty.Register("ImageSource", typeof(ImageSource), typeof(TextImageButton));
public ImageSource ImageSource
{
get => (ImageSource)GetValue(ImageSourceProperty);
set => SetValue(ImageSourceProperty, value);
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(TextImageButton));
public string Text
{
get => (string)GetValue(TextProperty);
set => SetValue(TextProperty, value);
}
public static readonly DependencyProperty IsDashedBorderProperty =
DependencyProperty.Register("IsDashedBorder", typeof(bool), typeof(TextImageButton), new PropertyMetadata(false, OnIsDashedBorderChanged));
public bool IsDashedBorder
{
get => (bool)GetValue(IsDashedBorderProperty);
set => SetValue(IsDashedBorderProperty, value);
}
private static void OnIsDashedBorderChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((TextImageButton)d).InvalidateVisual();
}
public TextImageButton()
{
DefaultStyleKey = typeof(TextImageButton);
}
}
}
TextImageButton.xaml 代码实现如下:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CustomControlLib.Buttons">
<Style TargetType="{x:Type local:TextImageButton}">
<Setter Property="Width" Value="60"/>
<Setter Property="Height" Value="60"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:TextImageButton}">
<Border x:Name="Border"
BorderBrush="Gray"
BorderThickness="1"
CornerRadius="8"
Background="Transparent"
SnapsToDevicePixels="true" Opacity="1" Width="{TemplateBinding Width}" Height="{TemplateBinding Height}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="35*"/>
<RowDefinition Height="65*"/>
</Grid.RowDefinitions>
<TextBlock x:Name="TextBlock" Grid.Row="0"
Text="{TemplateBinding Text}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="14"
Foreground="Black"
Opacity="1"/>
<Image x:Name="Image" Grid.Row="1"
Source="{TemplateBinding ImageSource}"
HorizontalAlignment="Center"
VerticalAlignment="Center" Margin="0 5 0 0" Opacity="1"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="LightGray" TargetName="Border"/>
<Setter Property="BorderThickness" Value="0" TargetName="Border"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="DarkGray" TargetName="Border"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="Gray"/>
<Setter Property="Background" Value="LightGray" TargetName="Border"/>
</Trigger>
<Trigger Property="IsDashedBorder" Value="True">
<Setter Property="IsEnabled" Value="false"/>
<Setter Property="Opacity" Value="0.6" TargetName="Border"/>
<Setter Property="Opacity" Value="0.6" TargetName="Image"/>
<Setter Property="Opacity" Value="0.6" TargetName="TextBlock"/>
<Setter Property="Foreground" Value="Gray"/>
<Setter Property="BorderBrush" TargetName="Border">
<Setter.Value>
<VisualBrush Stretch="Fill" TileMode="Tile">
<VisualBrush.Visual>
<Rectangle StrokeDashArray="2 1" Stroke="Gray" StrokeThickness="1" Width="50" Height="50"/>
</VisualBrush.Visual>
</VisualBrush>
</Setter.Value>
</Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
2、样式引用与封装
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/CustomControlLib;component/Themes/Buttons/IconFontButton.xaml" />
<ResourceDictionary Source="pack://application:,,,/CustomControlLib;component/Themes/Buttons/FontIconButton.xaml" />
<ResourceDictionary Source="pack://application:,,,/CustomControlLib;component/Themes/Buttons/ImageTextButton.xaml" />
<ResourceDictionary Source="pack://application:,,,/CustomControlLib;component/Themes/Buttons/TextImageButton.xaml" />
</ResourceDictionary.MergedDictionaries>
完成按钮样式后,只需要在 Generic.xaml 文件中引用 按钮样式即完成整个按钮的封装了,这样只要项目引用 自定义按钮库即可使用该自定义按钮了。
3、按钮案例演示
1、页面实现与文件创建
这里我们继续在上一节的按钮文件界面上增加样式布局即可,如下所示:
<Border Background="White" Grid.Row="2">
<Grid >
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Right">
<TextBlock Text="双按钮状态控制,边框同时虚线实线切换" FontSize="15" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="0 0 10 0"/>
<cc:ImageTextButton Text="开始生产" ToolTip="开始生产" IsDashedBorder="{Binding SystemStatus}" Command="{Binding ButtonClickCmd}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=Self},Path=ToolTip}" Width="70" Height="70" Margin="0,0,5,0" ImageSource="pack://application:,,,/Wpf_Examples;component/Assets/Images/Start.png"/>
<cc:ImageTextButton Text="停止生产" ToolTip="停止生产" IsDashedBorder="{Binding SystemStatus,Converter={StaticResource InverseBooleanConverter}}" Command="{Binding ButtonClickCmd}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=Self},Path=ToolTip}" Width="70" Height="70" Margin="0,0,5,0" ImageSource="pack://application:,,,/Wpf_Examples;component/Assets/Images/Stop.png"/>
</StackPanel>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Right" Grid.Row="1">
<TextBlock Text="单按钮状态控制,切换背景图片和文本" FontSize="15" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="0 0 10 0"/>
<cc:ImageTextButton Text="{Binding ButtonName}" Command="{Binding SingleButtonClickCmd}" ImageSource="{Binding ImageSource}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=Self},Path=Text}" Width="70" Height="70" Margin="0,0,5,0" />
</StackPanel>
</Grid>
<Grid Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Right">
<TextBlock Text="双按钮状态控制,边框同时虚线实线切换" FontSize="15" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="0 0 10 0"/>
<cc:TextImageButton Text="开始生产" ToolTip="开始生产" IsDashedBorder="{Binding SystemStatus}" Command="{Binding ButtonClickCmd}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=Self},Path=ToolTip}" Width="70" Height="70" Margin="0,0,5,0" ImageSource="pack://application:,,,/Wpf_Examples;component/Assets/Images/Start.png"/>
<cc:TextImageButton Text="停止生产" ToolTip="停止生产" IsDashedBorder="{Binding SystemStatus,Converter={StaticResource InverseBooleanConverter}}" Command="{Binding ButtonClickCmd}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=Self},Path=ToolTip}" Width="70" Height="70" Margin="0,0,5,0" ImageSource="pack://application:,,,/Wpf_Examples;component/Assets/Images/Stop.png"/>
</StackPanel>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Right" Grid.Row="1">
<TextBlock Text="单按钮状态控制,切换背景图片和文本" FontSize="15" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="0 0 10 0"/>
<cc:TextImageButton Text="{Binding ButtonName}" Command="{Binding SingleButtonClickCmd}" ImageSource="{Binding ImageSource}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=Self},Path=Text}" Width="70" Height="70" Margin="0,0,5,0" />
</StackPanel>
</Grid>
</Grid>
</Border>
ButtonViewModel.cs 后台功能代码实现如下:
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media.Imaging;
using Wpf_Examples.Views;
namespace Wpf_Examples.ViewModels
{
public class ButtonViewModel:ObservableObject
{
/// <summary>
/// 生产状态按钮名称
/// </summary>
private string buttonName;
public string ButtonName
{
get { return buttonName; }
set { SetProperty(ref buttonName, value); }
}
/// <summary>
/// 系统运行状态
/// </summary>
private bool systemStatus = false;
public bool SystemStatus
{
get { return systemStatus; }
set { SetProperty(ref systemStatus, value); }
}
/// <summary>
/// 产线状态
/// </summary>
private bool productStatus = false;
public bool ProductStatus
{
get { return productStatus; }
set { SetProperty(ref productStatus, value); }
}
/// <summary>
/// 生产状态背景图
/// </summary>
private BitmapImage imageSource;
public BitmapImage ImageSource
{
get { return imageSource; }
set { SetProperty(ref imageSource, value); }
}
public RelayCommand<string> ButtonClickCmd { get; set; }
public RelayCommand SingleButtonClickCmd { get; set; }
public ButtonViewModel() {
ButtonClickCmd = new RelayCommand<string>(BtnFun);
SingleButtonClickCmd = new RelayCommand(StatusChange);
StatusChange();
}
private void BtnFun(string obj)
{
switch (obj)
{
case "播放":
MessageBox.Show("播放按钮是假的,不能播放,哈哈哈哈.....","提示",MessageBoxButton.OK);
break;
case "错误":
MessageBox.Show("系统报错了,别怕,假的啦,哈哈哈哈.....", "提示", MessageBoxButton.OK);
break;
case "删除":
MessageBox.Show("想要删除我,那是不可能的,哈哈哈哈.....", "提示", MessageBoxButton.OK);
break;
case "开始生产":
SystemStatus = true;
break;
case "停止生产":
SystemStatus = false;
break;
}
}
private void StatusChange()
{
if (!ProductStatus)
{
ButtonName = "开始生产";
ImageSource = new BitmapImage(new Uri("pack://application:,,,/Wpf_Examples;component/Assets/Images/Start.png"));
ProductStatus = true;
}
else
{
ButtonName = "停止生产";
ImageSource = new BitmapImage(new Uri("pack://application:,,,/Wpf_Examples;component/Assets/Images/Stop.png"));
ProductStatus = false;
}
}
}
}
2、运行效果如下
4、源代码获取
源代码是整个按钮系类的全部代码。下载后可直接运行,按钮时独立封装在自定义控件类库中,任何项目只需要拷贝这个自定义控件库引用即可使用。
CSDN 源代码下载链接:多种类型的自定义按钮控件实现与封装