当前位置: 首页 > news >正文

WPF+MVVM案例实战(八)- 自定义开关控件封装实现

文章目录

  • 1、案例运行效果
  • 2、项目准备
  • 2、功能实现
    • 1、控件模板实现
    • 2、控件封装
      • 1、目录与文件创建
      • 2、各文件功能实现
  • 3、开关界面与主窗体菜单实现
    • 1、开关界面实现
    • 2、主窗体菜单实现
  • 4、源代码获取


1、案例运行效果

在这里插入图片描述

2、项目准备

打开项目 Wpf_Examples,新建ToggleButtonWindow.xmal 文件,这里没有 Wpf_Examples 项目的可以看下前面章节,WPF+MVVM案例实战(三)- 动态数字卡片效果实现 详细介绍了项目创建过程。
在这里插入图片描述

2、功能实现

1、控件模板实现

开关按钮基于CheckBox 按钮基础上修改控件模板实现。
ToggleButtonWindow.xaml 界面代码如下

<Window x:Class="Wpf_Examples.Views.ToggleButtonWindow"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:local="clr-namespace:Wpf_Examples.Views"mc:Ignorable="d"Title="ToggleButtonWindow" Height="450" Width="800" Background="#2B2B2B"><Window.Resources><Style x:Key="ToggleSwitchStyleChangeAnimate" TargetType="CheckBox"><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="CheckBox"><StackPanel Orientation="Horizontal"><Grid><Border CornerRadius="22" Width="80" Height="44" Background="LightGray"/><Border CornerRadius="18" x:Name="button" Width="36" Height="36" HorizontalAlignment="Left"/></Grid></StackPanel><ControlTemplate.Resources><Storyboard x:Key="toLeftStoryboard"><ThicknessAnimation Storyboard.TargetProperty="Margin" Storyboard.TargetName="button" From="40,0,0,0" To="4,0,0,0" Duration="0:0:0:0.3"><!--增加缓动处理,让切换效果更加平滑--><ThicknessAnimation.EasingFunction><CubicEase EasingMode="EaseInOut"/></ThicknessAnimation.EasingFunction></ThicknessAnimation></Storyboard><Storyboard x:Key="toRightStoryboard"><ThicknessAnimation Storyboard.TargetProperty="Margin" Storyboard.TargetName="button" From="4,0,0,0" To="40,0,0,0" Duration="0:0:0:0.3"><!--增加缓动处理,让切换效果更加平滑--><ThicknessAnimation.EasingFunction><CubicEase EasingMode="EaseInOut"/></ThicknessAnimation.EasingFunction></ThicknessAnimation></Storyboard></ControlTemplate.Resources><ControlTemplate.Triggers><Trigger Property="IsChecked" Value="False"><Trigger.EnterActions><RemoveStoryboard BeginStoryboardName="right"/><BeginStoryboard Storyboard="{StaticResource toLeftStoryboard}" x:Name="left"/></Trigger.EnterActions><Setter TargetName="button" Property="Background" Value="#737373"/></Trigger><Trigger Property="IsChecked" Value="True"><Trigger.EnterActions><RemoveStoryboard BeginStoryboardName="left"/><BeginStoryboard Storyboard="{StaticResource toRightStoryboard}" x:Name="right"/></Trigger.EnterActions><Setter TargetName="button" Property="Background" Value="#25DC2D"/></Trigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter></Style></Window.Resources><Grid HorizontalAlignment="Center"><CheckBox Style="{StaticResource ToggleSwitchStyleChangeAnimate}"/></Grid>
</Window>

2、控件封装

1、目录与文件创建

首先在自定义控件库 CustomControlLib 中新建一个 ToggleSwitch.cs 文件,在创建一个 Converters 文件夹,创建 ToggleSwitchConverter.cs 文件,这里用来做数据转换使用。如下图所示:
在这里插入图片描述

2、各文件功能实现

首先我们先实现开关按钮的样式定义,将前面 ToggleButtonWindow.xaml 中的 Style 样式拷贝到自定义控件的 Generic.xaml 文件中修改后如下所示:

<Style TargetType="{x:Type local:ToggleSwitch}"><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="CheckBox"><StackPanel Orientation="Horizontal"><Grid><Border Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" CornerRadius="{TemplateBinding Height,Converter={StaticResource ToggleSwitchConverter},ConverterParameter='OutSideCorner'}"Background="LightGray"/><Border x:Name="button" CornerRadius="{TemplateBinding Height,Converter={StaticResource ToggleSwitchConverter},ConverterParameter='InSideCorner'}"Width="{TemplateBinding Height,Converter={StaticResource ToggleSwitchConverter},ConverterParameter='ButtonSize'}"Height="{TemplateBinding Height,Converter={StaticResource ToggleSwitchConverter},ConverterParameter='ButtonSize'}"HorizontalAlignment="Left"/></Grid></StackPanel><ControlTemplate.Triggers><Trigger Property="IsChecked" Value="False"><Setter TargetName="button" Property="Background" Value="#737373"/></Trigger><Trigger Property="IsChecked" Value="True"><Setter TargetName="button" Property="Background" Value="{Binding Foreground,RelativeSource={RelativeSource TemplatedParent}}"/></Trigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter>
</Style>

样式代码主要是把按钮的宽高数据值绑定到原有按钮宽高属性上,通过转换器完成不同属性数据值的不同赋值,然后我们实现转换器 ToggleSwitchConverter.cs 的代码,如下所示:

public class ToggleSwitchConverter : IValueConverter
{public object Convert(object value, Type targetType, object parameter, CultureInfo culture){if (value is double height){var property = parameter as string;switch (property){case "ButtonSize":return (height - 8);case "OutSideCorner":return new CornerRadius(height/2);case "InSideCorner":return new CornerRadius((height-8) / 2);}}throw new NotImplementedException();}public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture){throw new NotImplementedException();}
}

最后,我们在 ToggleSwitch.cs 实现按钮的切换和动画加载功能代码,ToggleSwitch.cs 代码实现如下:

public class ToggleSwitch:CheckBox
{static ToggleSwitch(){DefaultStyleKeyProperty.OverrideMetadata(typeof(ToggleSwitch), new FrameworkPropertyMetadata(typeof(ToggleSwitch)));}public ToggleSwitch(){Checked += ToggleSwitch_Checked;Unchecked += ToggleSwitch_Unchecked;}private void ToggleSwitch_Checked(object sender, RoutedEventArgs e){Animatebutton(true);}private void ToggleSwitch_Unchecked(object sender, RoutedEventArgs e){Animatebutton(false);}private void Animatebutton(bool isChecked){if (GetTemplateChild("button") is Border button){Storyboard storyboard = new Storyboard();ThicknessAnimation animation = new ThicknessAnimation();animation.Duration=new Duration (TimeSpan.FromSeconds(0.3));animation.EasingFunction=new CircleEase { EasingMode = EasingMode.EaseOut };if (isChecked){animation.From = new Thickness(4, 0, 0, 0);animation.To=new Thickness(ActualWidth-(ActualHeight-8)-4, 0, 0, 0);}else{animation.To = new Thickness(4, 0, 0, 0);animation.From = new Thickness(ActualWidth - (ActualHeight - 8) - 4, 0, 0, 0);}Storyboard.SetTarget(animation,button); Storyboard.SetTargetProperty(animation,new PropertyPath(MarginProperty));storyboard.Children.Add(animation);if (isChecked){Resources.Remove("Left");Resources["Right"] = storyboard;}else{Resources.Remove("Right");Resources["Left"] = storyboard;}storyboard.Begin();}}}

3、开关界面与主窗体菜单实现

1、开关界面实现

ToggleButtonWindow.xaml 代码如下所示:

<Window x:Class="Wpf_Examples.Views.ToggleButtonWindow"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:cc="clr-namespace:CustomControlLib;assembly=CustomControlLib"xmlns:local="clr-namespace:Wpf_Examples.Views"mc:Ignorable="d"Title="ToggleButtonWindow" Height="450" Width="800" Background="#2B2B2B"><Window.Resources><Style x:Key="ToggleSwitchStyleChangeAnimate" TargetType="CheckBox"><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="CheckBox"><StackPanel Orientation="Horizontal"><Grid><Border CornerRadius="22" Width="80" Height="44" Background="LightGray"/><Border CornerRadius="18" x:Name="button" Width="36" Height="36" HorizontalAlignment="Left"/></Grid></StackPanel><ControlTemplate.Resources><Storyboard x:Key="toLeftStoryboard"><ThicknessAnimation Storyboard.TargetProperty="Margin" Storyboard.TargetName="button" From="40,0,0,0" To="4,0,0,0" Duration="0:0:0:0.3"><!--增加缓动处理,让切换效果更加平滑--><ThicknessAnimation.EasingFunction><CubicEase EasingMode="EaseInOut"/></ThicknessAnimation.EasingFunction></ThicknessAnimation></Storyboard><Storyboard x:Key="toRightStoryboard"><ThicknessAnimation Storyboard.TargetProperty="Margin" Storyboard.TargetName="button" From="4,0,0,0" To="40,0,0,0" Duration="0:0:0:0.3"><!--增加缓动处理,让切换效果更加平滑--><ThicknessAnimation.EasingFunction><CubicEase EasingMode="EaseInOut"/></ThicknessAnimation.EasingFunction></ThicknessAnimation></Storyboard></ControlTemplate.Resources><ControlTemplate.Triggers><Trigger Property="IsChecked" Value="False"><Trigger.EnterActions><RemoveStoryboard BeginStoryboardName="right"/><BeginStoryboard Storyboard="{StaticResource toLeftStoryboard}" x:Name="left"/></Trigger.EnterActions><Setter TargetName="button" Property="Background" Value="#737373"/></Trigger><Trigger Property="IsChecked" Value="True"><Trigger.EnterActions><RemoveStoryboard BeginStoryboardName="left"/><BeginStoryboard Storyboard="{StaticResource toRightStoryboard}" x:Name="right"/></Trigger.EnterActions><Setter TargetName="button" Property="Background" Value="#25DC2D"/></Trigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter></Style></Window.Resources><Grid HorizontalAlignment="Center"><StackPanel Orientation="Vertical"><CheckBox Style="{StaticResource ToggleSwitchStyleChangeAnimate}" Margin="0 20 0 20"/><cc:ToggleSwitch Width="80" Height="44" Foreground="#3CC330"  Margin="0 20 0 20"/><cc:ToggleSwitch Width="100" Height="60" Foreground="#E72114"/></StackPanel></Grid>
</Window>

上面我保留了原来的样式,然后也使用了封装控件的方式来展示相同效果。自定义控件可以通过改变属性设置,轻松实现不同按钮大小和选中颜色的设置,而模板样式只能实现一种效果。

2、主窗体菜单实现

MainWindow.xaml 菜单中添加新的按钮,代码如下:

 <Grid><WrapPanel><Button Width="100" Height="30" FontSize="18" Content="开关按钮" Command="{Binding ButtonClickCmd}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=Self},Path=Content}" Margin="8"/></WrapPanel></Grid>

MainViewModel.cs 的菜单功能按钮添加新的页面弹窗,代码如下:

 case "开关按钮":PopWindow(new ToggleButtonWindow());break;

4、源代码获取

CSDN 资源下载链接:自定义开关控件封装实现

http://www.lryc.cn/news/471071.html

相关文章:

  • 单机kafka性能需要高性能的硬件做支撑
  • Spark 的 Http Broadcast 和 Torrent Broadcast 广播实现类的对比
  • 030_Subplot_In_Matlab中多图绘制之subplot函数
  • 免费云服务器有什么使用限制和注意事项?
  • 3-ZYNQ 折腾记录 -PS_PL AXI Interfaces
  • 总结test
  • 在 On hold 期刊 eLife 上发表一篇生信文章需要什么工作量?
  • 使用Django框架开发企业级Web应用
  • 认识线程 — JavaEE
  • 【C++单调栈】853. 车队|1678
  • 第十届文荣奖华丽开幕,郁葱以青春与努力绽放青年演员光芒
  • CMake 生成器表达式介绍
  • ubuntu 20.04编译驱动报gcc-12 not found错误
  • docker sameersbn/bind dns服务器
  • 错误:无法推送一些引用到 ‘https://gitee.com/chek_kk/python-electron-app.git‘
  • 深度剖析美区代理IP的多元应用与优势
  • 基于KV260的基础视频链路通路(MIPI+Demosaic+VDMA)
  • Uni-App-04
  • ElasticSearch分片
  • spring高手之路
  • 工字钢与H型钢有什么区别?90%的工程师都搞错了!
  • 10个程序员可以接私活的平台(非常详细)零基础入门到精通,收藏这篇就够了
  • 小程序云开发CMS新版数据模型讲解,可视化网页管理后台,内容管理对数据库进行增删改查操作,新闻小程序实战学习
  • undertow服务器初始化
  • LeetCode9:回文数
  • 模板语法(2)
  • 从头学PHP之数组输出基本函数
  • 基于SSM+小程序的4S店客户管理系统(汽车2)
  • ZYNQ AXI_Timer 中断
  • UE5之5.4 第一人称示例代码阅读2 子弹发射逻辑