WPF-实现按钮的动态变化

news/2025/3/20 16:24:26/
  1. MVVM 模式基础
    • 视图模型(ViewModel)MainViewModel类作为视图模型,封装了与视图相关的属性和命令。它实现了INotifyPropertyChanged接口,当属性值发生改变时,通过OnPropertyChanged方法通知视图进行更新,确保视图与数据的一致性。
    • 视图(View):在 XAML 文件中定义,通过数据绑定将ButtonWidthHeight属性与视图模型的ButtonWidthButtonHeight属性关联起来,实现视图对数据的展示。同时,将按钮的点击事件绑定到视图模型的ResizeButtonCommand命令,使视图的交互操作能触发视图模型中的逻辑。
  2. 动画创建与管理
    • Storyboard 初始化:在视图模型的InitializeStoryboard方法中,创建了一个Storyboard对象_resizeStoryboard,用于管理和协调多个动画。
    • DoubleAnimation 创建:为按钮的宽度和高度变化分别创建了DoubleAnimation对象。这些动画定义了从初始值(From属性)到目标值(To属性)的过渡,这里目标值是初始值的 1.5 倍。动画的持续时间由Duration属性设置为 0.5 秒,AutoReverse属性设置为true,使动画在到达目标值后自动反向播放,RepeatBehavior属性设置为RepeatBehavior.Forever,让动画无限循环。
  3. 命令绑定与参数传递
    • MyCommand 实现:定义了MyCommand类来实现ICommand接口,该类允许将一个Action<object>作为参数传递给构造函数,在按钮点击时执行相应的逻辑。
    • 命令绑定:在视图模型的构造函数中,将ResizeButtonCommand初始化为MyCommand的实例,并关联到ExecuteResizeButtonCommand方法,该方法处理按钮点击后的逻辑。
    • 参数传递:在视图中,通过CommandParameter="{Binding ElementName=PART_Button}"将按钮自身作为参数传递给命令。在视图模型的ExecuteResizeButtonCommand方法中,通过判断参数类型来获取按钮实例,以便正确设置动画目标和启动动画。
  4. 事件处理与状态管理
    • 点击事件处理ExecuteResizeButtonCommand方法负责处理按钮的点击事件。它根据_isAnimating标志判断当前动画状态,若正在动画,则停止动画并将按钮大小恢复到初始值;若未动画,则启动动画。每次点击按钮时,都会切换_isAnimating标志的值,以记录动画状态。

      5.代码

MainWindow.xaml

<Window x:Class="WpfAppButtonResize.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:local="clr-namespace:WpfAppButtonResize"xmlns:local2="clr-namespace:WpfAppButtonResize.ViewModel"mc:Ignorable="d"Title="MainWindow" Height="350" Width="525"><Window.DataContext><local2:MainWindowViewModel/></Window.DataContext><Grid><Button Content="点击我" Width="{Binding ButtonWidth}" Height="{Binding ButtonHeight}" Command="{Binding ResizeButtonCommand}"CommandParameter="{Binding ElementName=PART_Button}"Name="PART_Button"/></Grid>
</Window>

MainWindowViewModel.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.Input;
using System.Windows.Media.Animation;namespace WpfAppButtonResize.ViewModel
{public class MainWindowViewModel:Notify{private double _buttonWidth = 100;private double _buttonHeight = 50;private bool _isAnimating = false;private Storyboard _resizeStoryboard;public double ButtonWidth{get { return _buttonWidth; }set{_buttonWidth = value;OnPropertyChanged();}}public double ButtonHeight{get { return _buttonHeight; }set{_buttonHeight = value;OnPropertyChanged();}}public ICommand ResizeButtonCommand { get; private set; }public MainWindowViewModel(){ResizeButtonCommand = new MyCommand(ExecuteResizeButtonCommand);InitializeStoryboard();}private void InitializeStoryboard(){_resizeStoryboard = new Storyboard();// 宽度动画DoubleAnimation widthAnimation = new DoubleAnimation{From = _buttonWidth,To = _buttonWidth * 1.5,Duration = TimeSpan.FromSeconds(0.5),AutoReverse = true,RepeatBehavior = RepeatBehavior.Forever};// 这里后续在设置目标时会修正_resizeStoryboard.Children.Add(widthAnimation);// 高度动画DoubleAnimation heightAnimation = new DoubleAnimation{From = _buttonHeight,To = _buttonHeight * 1.5,Duration = TimeSpan.FromSeconds(0.5),AutoReverse = true,RepeatBehavior = RepeatBehavior.Forever};_resizeStoryboard.Children.Add(heightAnimation);}private void ExecuteResizeButtonCommand(object parameter){if (parameter is Button button){if (_isAnimating){_resizeStoryboard.Stop();ButtonWidth = 100;ButtonHeight = 50;}else{// 设置宽度动画的目标和属性路径Storyboard.SetTarget(_resizeStoryboard.Children[0] as DoubleAnimation, button);Storyboard.SetTargetProperty(_resizeStoryboard.Children[0] as DoubleAnimation, new PropertyPath("(FrameworkElement.Width)"));// 设置高度动画的目标和属性路径Storyboard.SetTarget(_resizeStoryboard.Children[1] as DoubleAnimation, button);Storyboard.SetTargetProperty(_resizeStoryboard.Children[1] as DoubleAnimation, new PropertyPath("(FrameworkElement.Height)"));_resizeStoryboard.Begin();}_isAnimating = !_isAnimating;}}}
}

MyCommand.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;namespace WpfAppButtonResize
{public class MyCommand : ICommand{private readonly Action _execute;private readonly Action<object> _execute2;private readonly Func<bool> _canExecute;public MyCommand(Action<object> execute){_execute2 = execute;}public MyCommand(Action execute, Func<bool> canExecute = null){_execute = execute;_canExecute = canExecute;}public event EventHandler CanExecuteChanged{add { CommandManager.RequerySuggested += value; }remove { CommandManager.RequerySuggested -= value; }}public bool CanExecute(object parameter){return _canExecute == null || _canExecute();}public void Execute(object parameter){if (_execute != null){_execute();}else if (_execute2 != null){_execute2(parameter);}}}
}

Notify.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;namespace WpfAppButtonResize
{public abstract class Notify : INotifyPropertyChanged{public event PropertyChangedEventHandler PropertyChanged;public void OnPropertyChanged([CallerMemberName] string name = null){PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));}}
}


http://www.ppmy.cn/news/1580637.html

相关文章

[蓝桥杯 2023 省 B] 飞机降落(不会dfs的看过来)

[蓝桥杯 2023 省 B] 飞机降落 题目描述 N N N 架飞机准备降落到某个只有一条跑道的机场。其中第 i i i 架飞机在 T i T_{i} Ti​ 时刻到达机场上空&#xff0c;到达时它的剩余油料还可以继续盘旋 D i D_{i} Di​ 个单位时间&#xff0c;即它最早可以于 T i T_{i} Ti​ 时刻…

Web爬虫利器FireCrawl:全方位助力AI训练与高效数据抓取

Web爬虫利器FireCrawl&#xff1a;全方位助力AI训练与高效数据抓取 一、FireCrawl 项目简介二、主要功能三、FireCrawl应用场景1. 大语言模型训练2. 检索增强生成&#xff08;RAG&#xff09;&#xff1a;3. 数据驱动的开发项目4. SEO 与内容优化5. 在线服务与工具集成 四、安装…

深度学习有哪些算法?

深度学习包含多种算法和模型&#xff0c;广泛应用于图像处理、自然语言处理、语音识别等领域。以下是主要分类及代表性算法&#xff1a; 一、基础神经网络 多层感知机&#xff08;MLP&#xff09; 最简单的深度学习模型&#xff0c;由多个全连接层组成&#xff0c;用于分类和回…

软件安全性测试的重要性和常用工具介绍,软件测试服务公司推荐

在当今数字化快速发展的时代&#xff0c;软件已经成为各行各业不可或缺的一部分。然而&#xff0c;随着软件系统的复杂性增加&#xff0c;安全性问题也愈发突出&#xff0c;因此软件产品生产周期中安全测试必不可少。软件安全性测试是指对软件系统进行评估&#xff0c;以发现潜…

领略算法真谛:01背包问题

嘿&#xff0c;各位技术潮人&#xff01;好久不见甚是想念。生活就像一场奇妙冒险&#xff0c;而编程就是那把超酷的万能钥匙。此刻&#xff0c;阳光洒在键盘上&#xff0c;灵感在指尖跳跃&#xff0c;让我们抛开一切束缚&#xff0c;给平淡日子加点料&#xff0c;注入满满的pa…

docker overlay2 文件夹比较大怎么处理

overlay2 是 Docker 默认的存储驱动&#xff0c;用于管理容器和镜像的存储。当 overlay2 文件夹变得非常大时&#xff0c;通常是由于以下原因&#xff1a; 未清理的镜像和容器&#xff1a;未使用的镜像、停止的容器、悬空的卷等占用了大量空间。日志文件过大&#xff1a;容器生…

STM32原理性知识

文章目录 1、如何在STM32 实现原子操作 2、寄存器是什么&#xff1f;为什么向外设地址写值可以控制外设的状态&#xff1f; 1、如何在STM32 实现原子操作 在CMSIS模块中已经提供了原子操作宏&#xff0c;用于操作16位或32位变量&#xff0c;包括ATOMIC_SET_BIT、ATOMIC_CLEAR_…

C++ 语法之函数和函数指针

在上一章中 C 语法之 指针的一些应用说明-CSDN博客 我们了解了指针变量&#xff0c;int *p;取变量a的地址这些。 那么函数同样也有个地址&#xff0c;直接输出函数名就可以得到地址&#xff0c;如下&#xff1a; #include<iostream> using namespace std; void fun() …