文章目录
- @[TOC](文章目录)
- 1、创建项目
- 2、创建自定义控件类库
- 3、实现自定义控件
- 1. ImageTextButton 依赖属性实现
- 2.样式模板实现
- 4、引用自定义控件库
- 5、UI及功能实现
- 1、 前端UI实现
- 2、状态转换器 InverseBooleanConverter 实现
- 3、MainViewModel.cs 实现
- 6、运行效果
- 7、源代码获取
文章目录
- @[TOC](文章目录)
- 1、创建项目
- 2、创建自定义控件类库
- 3、实现自定义控件
- 1. ImageTextButton 依赖属性实现
- 2.样式模板实现
- 4、引用自定义控件库
- 5、UI及功能实现
- 1、 前端UI实现
- 2、状态转换器 InverseBooleanConverter 实现
- 3、MainViewModel.cs 实现
- 6、运行效果
- 7、源代码获取
1、创建项目
打开 VS2022 ,新建项目 Wpf_Examples,创建各层级文件夹,安装 CommunityToolkit.Mvvm 和 Microsoft.Extensions.DependencyInjectio NuGet包,完成MVVM框架搭建。搭建完成后项目层次如下图所示:
这里如何实现 MVVM 框架可以参考本人 像 MvvmLight 一样使用 CommunityToolkit.Mvvm 工具包 的文章
2、创建自定义控件类库
新建WPF自定义控件类库 CustomControlLib ,注意是自定义控件类库,不是用户控件库,如下图所示:
3、实现自定义控件
1. ImageTextButton 依赖属性实现
代码如下(示例):
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
{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);}}
}
2.样式模板实现
代码如下(示例):
<ResourceDictionaryxmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:local="clr-namespace:CustomControlLib"><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"/></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>
4、引用自定义控件库
将自定义控件库添加到项目引用,如下所示:
5、UI及功能实现
1、 前端UI实现
MainWindow.xaml 代码如下所示:
<Window x:Class="Wpf_Examples.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:converter="clr-namespace:Wpf_Examples.Converters"xmlns:local="clr-namespace:Wpf_Examples"xmlns:cc="clr-namespace:CustomControlLib;assembly=CustomControlLib"DataContext="{Binding Source={StaticResource Locator},Path=Main}"mc:Ignorable="d"Title="MainWindow" Height="450" Width="800"><Window.Resources><converter:StatusToColorConverter x:Key="StatusToColorConverter"/><converter:InverseBooleanConverter x:Key="InverseBooleanConverter"/></Window.Resources><Grid><Grid.RowDefinitions><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition/><RowDefinition Height="50"/></Grid.RowDefinitions><StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Right"><TextBlock Text="双按钮状态控制,边框同时虚线实线切换" FontSize="30" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="0 0 80 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="30" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="0 0 80 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.Row="3"><Grid.ColumnDefinitions><ColumnDefinition/><ColumnDefinition/><ColumnDefinition/></Grid.ColumnDefinitions><StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Right"><TextBlock Text="网络" FontSize="16" Foreground="DarkGray" Margin="0 0 20 0"/><Ellipse Width="20" Height="20" Fill="{Binding NetStatusValue, Converter={StaticResource StatusToColorConverter}}"/></StackPanel><StackPanel Grid.Column="1" Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center"><TextBlock Text="PLC" FontSize="16" Foreground="DarkGray" Margin="0 0 20 0"/><Ellipse Width="20" Height="20" Fill="{Binding PLCStatusValue, Converter={StaticResource StatusToColorConverter}}"/></StackPanel><StackPanel Grid.Column="2" Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Left"><TextBlock Text="相机" FontSize="16" Foreground="DarkGray" Margin="0 0 20 0"/><Ellipse Width="20" Height="20" Fill="{Binding DevStatusValue, Converter={StaticResource StatusToColorConverter}}"/></StackPanel></Grid></Grid>
</Window>
2、状态转换器 InverseBooleanConverter 实现
代码如下:
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;namespace Wpf_Examples.Converters
{public class InverseBooleanConverter : IValueConverter{public object Convert(object value, Type targetType, object parameter, CultureInfo culture){return !(value is bool boolValue) || !boolValue;}public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture){return !(value is bool boolValue) || !boolValue;}}
}
3、MainViewModel.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.Media.Imaging;
using System.Windows.Threading;namespace Wpf_Examples.ViewModels
{public class MainViewModel : ObservableObject{/// <summary>/// 网络状态按钮名称/// </summary>private int netStatusValue = 2;public int NetStatusValue{get { return netStatusValue; }set { SetProperty(ref netStatusValue, value); }}/// <summary>/// PLC状态按钮名称/// </summary>private int plcStatusValue = 1;public int PLCStatusValue{get { return plcStatusValue; }set { SetProperty(ref plcStatusValue, value); }}/// <summary>/// 设备状态/// </summary>private int devStatusValue = 0;public int DevStatusValue{get { return devStatusValue; }set { SetProperty(ref devStatusValue, value); }}/// <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 MainViewModel(){ButtonClickCmd = new RelayCommand<string>(FunMenu);SingleButtonClickCmd = new RelayCommand(StatusChange);CreateTimer();StatusChange();}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;}}private void FunMenu(string obj){string menu = obj as string;switch (menu){case "开始生产":SystemStatus = true;break;case "停止生产":SystemStatus = false;break;}}private void CreateTimer(){#region 每秒定时器服务DispatcherTimer cpuTimer = new DispatcherTimer{Interval = new TimeSpan(0, 0, 0, 3, 0)};cpuTimer.Tick += DispatcherTimer_Tick;cpuTimer.Start();#endregion}private void DispatcherTimer_Tick(object sender, EventArgs e){DevStatusValue = StatusChange(DevStatusValue);NetStatusValue = StatusChange(NetStatusValue);PLCStatusValue = StatusChange(PLCStatusValue);}private int StatusChange(int value){int outVal = 0;//状态变化if (value == 0){outVal = 1;}else if (value == 1){outVal = 2;}else{outVal = 0;}return outVal;}}
}
6、运行效果
7、源代码获取
CSDN链接:WPF+MVVM案例实战-自定义按钮实现(带图片文字虚线实线边框切换)