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

wpf 基于Behavior库 的行为模块

Microsoft.Xaml.Behaviors 是一个用于WPF(Windows Presentation Foundation)的行为库,它的主要作用是允许开发者在不修改控件源代码的情况下,为控件添加自定义的行为和交互逻辑。行为库的核心思想是通过定义可重用的行为组件,将交互逻辑与UI控件解耦,从而提高代码的可维护性和可复用性。


1. 增强控件功能

  • 无需修改控件源码:在WPF中,控件的功能通常是固定的,但如果需要扩展控件的功能(例如为按钮添加双击事件、为文本框添加自动完成功能等),可以通过行为库来实现,而无需修改控件的源代码。
  • 动态添加行为:行为可以动态地附加到控件上,并在运行时生效,非常适合需要灵活交互的场景。

2. 将交互逻辑与UI解耦

  • 行为与UI分离:行为库使得交互逻辑与UI控件分离,开发者可以在不侵入控件代码的情况下,为控件添加自定义逻辑。
  • 行为复用:一旦定义了一个行为,它可以被多次复用到不同的控件上,减少了重复代码的编写。

3. 简化复杂的交互逻辑

  • 复杂交互的封装:某些复杂的交互逻辑(例如拖放操作、窗口关闭时的特殊处理、动画触发等)可以通过行为库封装为一个独立的行为,而不是直接写入控件的事件处理程序中。
  • 避免事件处理代码膨胀:使用行为库可以将事件处理逻辑集中管理,避免在代码背后堆积大量的事件处理代码。

4. 支持MVVM模式

  • MVVM的桥梁:在MVVM模式中,Behavior 可以作为视图(View)和视图模型(ViewModel)之间的桥梁。行为可以直接绑定到ViewModel中的命令(ICommand),从而将用户的交互操作(例如按钮点击、窗口关闭等)映射到ViewModel中的业务逻辑。
  • 减少代码背后的复杂性:在MVVM中,行为可以代替代码背后的逻辑(例如事件处理程序),使得代码更加清晰和简洁。

5. 灵活性和可扩展性

  • 自定义行为:开发者可以根据需求创建自定义的行为类,继承自 Behavior<T>(其中 T 是目标控件的类型,例如 ButtonTextBoxWindow 等)。
  • 内置行为Microsoft.Xaml.Behaviors 库还包含一些预定义的行为,例如 EventTriggerInvokeCommandAction 等,可以直接使用。

6. 与XAML无缝集成

  • 在XAML中使用行为:行为库可以与XAML无缝集成,开发者可以直接在XAML中为控件附加行为,而不需要编写C#代码。
    <Button>
        <i:Interaction.Behaviors>
            <behaviors:MyCustomBehavior />
        </i:Interaction.Behaviors>
    </Button>
    
  • 绑定支持:行为可以绑定到ViewModel中的命令或属性,使得行为逻辑可以动态变化。

示例:使用行为库的场景

  1. 拖放操作:为控件添加拖放行为。
  2. 窗口关闭时的特殊处理:如您提供的代码示例,当窗口关闭时,可以执行自定义命令(例如隐藏窗口而不是关闭它)。
  3. 按钮双击事件:为按钮添加双击行为,而不需要修改按钮的默认行为。
  4. 动画触发:当某个事件发生时(例如鼠标悬停),触发控件的动画。
  5. 自动完成:为文本框添加自动完成行为。

窗口关闭时的特殊处理

附加属性快捷键 : propdp

public static readonly DependencyProperty ClosingActionProperty =
    DependencyProperty.Register(
        "ClosingAction",          // 属性名称
        typeof(ICommand),         // 属性类型
        typeof(HideViewBehavior), // 属性的宿主类 这里指定依赖属性的宿主类是 HideViewBehavior,表示这个依赖属性是属于 HideViewBehavior 类的。
        new PropertyMetadata(null) // 属性元数据 默认值为null
    );
using CommunityToolkit.Mvvm.Input;
using Microsoft.Xaml.Behaviors;
using System.Windows;
using System.Windows.Input;

namespace BehaviorsModule
{
    public class HideViewBehavior : Behavior<Window>
    {
        public ICommand ClosingAction
        {
            get { return (ICommand)GetValue(ClosingActionProperty); }
            set { SetValue(ClosingActionProperty, value); }
        }

        public static readonly DependencyProperty ClosingActionProperty =
            DependencyProperty.Register("ClosingAction", typeof(ICommand), typeof(HideViewBehavior), new PropertyMetadata(null));



        protected override void OnAttached()
        {
            base.OnAttached();

            AssociatedObject.Closing += AssociatedObject_Closing;
        }

        private void AssociatedObject_Closing(object? sender, System.ComponentModel.CancelEventArgs e)
        {
            e.Cancel = true;

            if (ClosingAction != null)
            {
                ClosingAction.Execute(new object());
            }
        }


    }
}

给控件添加拖放操作

using Microsoft.Xaml.Behaviors;
using System.Windows;
using System.Windows.Input;


namespace BehaviorsModule
{
    public class MoveViewBehavior: Behavior<Window>
    {
        protected override void OnAttached()
        {
            base.OnAttached();

            AssociatedObject.PreviewMouseDown += AssociatedObject_PreviewMouseDown;

            AssociatedObject.PreviewMouseMove += AssociatedObject_PreviewMouseMove;

            AssociatedObject.PreviewMouseLeftButtonUp += AssociatedObject_PreviewMouseLeftButtonUp;
        }

        private void AssociatedObject_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (_isDragMoved)
            {
                _isDragMoved = false;
                e.Handled = true;
            }
        }

        private void AssociatedObject_PreviewMouseMove(object sender, MouseEventArgs e)
        {
            if (Mouse.LeftButton == MouseButtonState.Pressed && _pressedPosition != e.GetPosition(AssociatedObject))
            {
                _isDragMoved = true;
                AssociatedObject.DragMove();
            }
        }

        Point _pressedPosition;
        bool _isDragMoved = false;
        private void AssociatedObject_PreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
            _pressedPosition = e.GetPosition(AssociatedObject);
        }
    }
}

初始化窗体位置

    public class InitViewPostionBehavior : Behavior<Window>
    {
        public double xp
        {
            get 
            { 
                return (double)GetValue(xpProperty);
            }
            set { SetValue(xpProperty, value); }
        }

        // Using a DependencyProperty as the backing store for xp.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty xpProperty =
            DependencyProperty.Register("xp", typeof(double), typeof(InitViewPostionBehavior), new PropertyMetadata(0.0));


        public double yp
        {
            get 
            { return (double)GetValue(ypProperty); }
            set { SetValue(ypProperty, value); }
        }

        // Using a DependencyProperty as the backing store for yp.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ypProperty =
            DependencyProperty.Register("yp", typeof(double), typeof(InitViewPostionBehavior), new PropertyMetadata(0.0));


        private void InitializeFormPosition()
        {
            var workingArea = SystemParameters.WorkArea;
            double screenWidth = workingArea.Width;
            double screenHeight = workingArea.Height;

            double x = screenWidth / xp;
            double y = screenHeight / yp;

            AssociatedObject.Left = x;
            AssociatedObject.Top = y;
        }

        protected override void OnAttached()
        {
            base.OnAttached();
            InitializeFormPosition();
        }
    }

http://www.kler.cn/a/461543.html

相关文章:

  • STM32 拓展 RTC(实时时钟)
  • C# 服务调用RFC函数获取物料信息,并输出生成Excel文件
  • Android 第三方框架:网络框架:OkHttp:源码分析:缓存
  • 快速上手LangChain(三)构建检索增强生成(RAG)应用
  • Spring源码分析之事件机制——观察者模式(三)
  • 禁用div的写法(自定义disabled)Vue3
  • 网络安全 | 物联网安全:从设备到网络的全方位防护
  • day 29 进程exec函数族 ,进程实现无人机模块,exec实现minishell
  • Ribbon和Eureka的集成
  • 黑神话悟空游戏鼠标光标使用教程与下载
  • 探秘Kafka源码:关键内容解析
  • 【Leetcode 热题 100】22. 括号生成
  • 设计模式-创建型模式-工厂模式
  • 【Git_bugs】remote error GH013 Repository rule violations found for.md
  • 【网络】什么是路由协议(Routing Protocols)?常见的路由协议包括RIP、OSPF、EIGRP和BGP
  • ESP8266+STM32+阿里云保姆级教程(AT指令+MQTT)
  • 随笔 | 写在2024的最后一天
  • 线程锁和协程锁的区别
  • Redis Stream:实时数据处理的高效解决方案
  • 2分钟知晓Vscode 插件发布流程
  • 【Rust自学】8.6. HashMap Pt.2:更新HashMap
  • 智能运维分析决策系统:构建高效运维的新篇章
  • 自动化与人工结合:如何平衡效率与风险?
  • 监控 Docker 注册表
  • 基于 Slf4j 和 AOP 的自动化方法执行时间日志记录方案
  • python-Flask:SQLite数据库路径不正确但是成功访问到了数据库,并对表进行了操作