WPF MvvmLight

news2024/11/16 7:41:28

关于

停止更新

官网:http://www.mvvmlight.net/

源码地址:GitHub - lbugnion/mvvmlight: The main purpose of the toolkit is to accelerate the creation and development of MVVM applications in Xamarin.Android, Xamarin.iOS, Xamarin.Forms, Windows 10 UWP, Windows Presentation Foundation (WPF), Silverlight, Windows Phone.、https://archive.codeplex.com/?p=mvvmlight(迁移到Github)

开始

通过Nuget平台,引入相关库

框架中的数据与行为
数据绑定与通知:INotifyPropertyChanged

默认:自定义

框架:ObservableObject、ViewModelBase(VM的资源释放)

Model:

public class MainModel : ObservableObject { }

ViewModel:

通知方式:RaisePropertyChanged、Set

public class MainViewModel : ViewModelBase 
{
     private string _value = "Hello";

     public string Value
     {
         get { return _value; }
         set
         {
             // 第一种通知方式
             //this.RaisePropertyChanged();
             //_value = value;
    
             // 第二种通知方式 建议第二种
             Set<string>(ref _value, value);
         }
     }
    // 作用:统一执行对象的资源清理 VM的释放
    // View关闭退出的时候 后台线程需要结束
    public override void Cleanup()
    {
        base.Cleanup();
    }
}

Cleanup:统一执行对象的资源清理 VM的释放

手写MvvmLight中的值通知方法
 public class NotifyBase : INotifyPropertyChanged
 {
     public event PropertyChangedEventHandler? PropertyChanged;

     public void SetProperty<T>(ref T propertyName,T value, [CallerMemberName] string propName = "")
     {
         if (propertyName is null || !propertyName.Equals(value))
         {
             propertyName = value;
             PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
         }
     }
 }
命令绑定对象:ICommand

默认:自定义

框架:RelayCommand、RelayCommand<T>

 public RelayCommand BtnCommand { get; set; }
 public RelayCommand<object> BtnParamCommand { get; set; }

public MainViewModel()
{

    // 第二个参数:按钮是否可以点击按钮状态
    BtnCommand = new RelayCommand(DoButtonCommand, DoButtonStatus);
    BtnParamCommand = new RelayCommand<object>(DoBtnParamCommand);
}

 private void DoButtonCommand()
 {

 }
  
 private bool DoButtonStatus()
 {
     return Value == "Hello";
 }

 private void DoBtnParamCommand(object obj)
 {
     
 }
设计模式IsInDesignMode
if (this.IsInDesignMode)
{
    // 设计时 模拟数据处理 
}
else
{
    // 运行时执行
}
设计模式也可以用xaml写:
<Window x:Class="XH.MvvmLightLesson.Views.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:XH.MvvmLightLesson.Views"
  mc:Ignorable="d" 
  xmlns:vm="clr-namespace:XH.MvvmLightLesson.ViewModels"
  Title="MainWindow" Height="450" Width="800">
  <!--d:也是设计时的显示,运行不显示-->
  <d:Window.DataContext>
    <vm:MainViewModel />
  </d:Window.DataContext>
</Window>
扩展对象
Messenger:

解决对象间的逻辑调用(使得VM可以调用View层面的对象)

注册(委托方法)、发布(主动请求执行这个委托方法)、反注册

注册:在主窗口或者APP.xaml.cs中写方法,主要是View层面的注册

 public MainWindow()
 {
     InitializeComponent();

     // MvvmLight基本的注册过程
     Messenger.Default.Register<string>(this, ExecuteMessage);

     // 如果需要区分这两个执行逻辑 两个方法:
     // 1、使用Token(Key)
     Messenger.Default.Register<string>(this,"SubWin", ExecuteMessageSubWin);
     // 2、使用类型区分 复杂的数据传参
     Messenger.Default.Register<Base.MessageBase>(this, ExecuteMessageType);
 }
private void ExecuteMessageType(Base.MessageBase obj)
{
    var result = new SubWindow { Owner = this }.ShowDialog() == true;

    obj.Action?.Invoke(result);
}

private void ExecuteMessageSubWin(string obj)
{
    new SubWindow { Owner = this }.ShowDialog();
}

复杂类型类:这里用了更加复杂的委托

 public class MessageBase
 {
     public string Value { get; set; }
     public Action<bool> Action { get; set; }
 }

发布(主动请求):

private void DoBtnParamCommand(object obj)
{
    // 主动 发布
    // 根据类型绑定、Key
    //Messenger.Default.Send<string>(Value);
    //Messenger.Default.Send<string>(Value, "SubWin");
    Messenger.Default.Send<Base.MessageBase>(new Base.MessageBase { Value = Value, 
        Action = GetResult });
}
private void GetResult(bool obj)
{

}

顺序:

Register -->Send -->ExecuteMessageType-->GetResult

DispatcherHelper

跨线程、初始化、应用中任意地方调用

DispatcherHelper初始化:在APP中初始化

public partial class App : Application
{
    public App()
    {
        // DispatcherHelper 初始化
        DispatcherHelper.Initialize();
    }
}

使用:再需要跨线程使用的时候,使用此方法:

 Task.Run(async () =>
 {
     await Task.Delay(2000);
     while (true)
     {
         DispatcherHelper.CheckBeginInvokeOnUI(() =>
         {
             ValueList.Add($"Xiao Hai{ValueList.Count}");
         });
         // 和下方方法一样
         //Application.Current.Dispatcher.Invoke(() =>
         //{
         //    ValueList.Add($"Xiao Hai{ValueList.Count}");
         //});
     }
 });

注意:

DispatcherHelper.CheckBeginInvokeOnUI:异步执行

Application.Current.Dispatcher.Invoke:同步执行

SimpleIoC

在全局APP.xaml中使用

 <Application.Resources>
     <ResourceDictionary>
         <vm:ViewModelCenter x:Key="Center" />
     </ResourceDictionary>
 </Application.Resources>

ViewModelCenter中写法:

public class ViewModelCenter
{
    SimpleIoc _simpleIoc = SimpleIoc.Default;

    public ViewModelCenter()
    {
        // 注册一个Ioc实例
        _simpleIoc.Register<IDataAccess, MySqlDA>();
        _simpleIoc.Register<MainViewModel>();
        _simpleIoc.Register<SubViewModel>();

        // 创建多个实例 untiy  --  key
        // SimpleIoc:不可以重复创建实例
        //_simpleIoc.Register<IDataAccess,SqlServerDA>();

    }

    // GetInstance:获取一个实例
    public MainViewModel MainWin { get => _simpleIoc.GetInstance<MainViewModel>(); }
    public SubViewModel SubWin { get => _simpleIoc.GetInstance<SubViewModel>(); }
}

在页面xaml中,数据传达方式:

DataContext="{Binding Source={StaticResource Center},Path=MainWin}"

总结:

IOC就当与是个容器,可以在全局中设置一些数据的初始化,可以直接在构造函数中进行传入已经实例化的全局对象,切记对象在IOC中已经实例化,并且只能实例化一次,不会重复实例化。

自定义IOC:
 public class XiaohaiIoc
 {
     private static XiaohaiIoc _default;
     private static readonly object _instanceLock = new object();
     // IOC初始化
     public static XiaohaiIoc Default
     {
         get
         {
             if (_default == null)
             {
                 lock (_instanceLock)
                 {
                     if (_default == null)
                     {
                         _default = new XiaohaiIoc();
                     }
                 }
             }
             return _default;
         }
     }
     // 防止被初始化new 
     private XiaohaiIoc() { }
     
     Dictionary<string, Type> _objectDic = new Dictionary<string, Type>();
     
     public void Register<T>()
     {
         _objectDic.Add(typeof(T).FullName!, typeof(T));
     }
     // TTo 必须继承或引用 TFrom
     public void Register<TFrom, TTo>() where TTo : TFrom
     {
         _objectDic.Add(typeof(TFrom).FullName!, typeof(TTo));
     }
     public T Resolve<T>()
     {
         string key = typeof(T).FullName!;
         if (_objectDic.ContainsKey(key))
         {
             // 创建新的实例 并返回
             return (T)Activator.CreateInstance(_objectDic[key])!;
         }
         else
             return default(T)!;
     }
 }

缺点:每次掉用都是新的实例,每次都初始化,导致数据会丢失

优化:单例的IOC容器:

using GalaSoft.MvvmLight.Ioc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace XH.MvvmLightLesson.Base
{
    public class XiaohaiIoc
    {
        private static XiaohaiIoc _default;
        // 防止重复初始化new 对象,加个锁
        private static readonly object _instanceLock = new object();
        // 初始化 ioc
        public static XiaohaiIoc Default
        {
            get
            {
                if (_default == null)
                {
                    lock (_instanceLock)
                    {
                        if (_default == null)
                        {
                            _default = new XiaohaiIoc();
                        }
                    }
                }
                return _default;
            }
        }
        // 防止外面初始化此ioc
        private XiaohaiIoc() { }
        Dictionary<string, InstenceModel> _instenceDic = new Dictionary<string, InstenceModel>();

        public void RegisterSingle<T>()
        {
            _instenceDic.Add(typeof(T).FullName!,
                new InstenceModel
                {
                    ObjectType = typeof(T)
                });
        }

        public void RegisterSingle<TFrom, TTo>() where TTo : TFrom
        {
            _instenceDic.Add(typeof(TFrom).FullName!, new InstenceModel
            {
                ObjectType = typeof(TTo)
            });
        }

        public T ResolveSingle<T>()
        {
            string key = typeof(T).FullName!;
            if (_instenceDic.ContainsKey(key))
            {
                if (_instenceDic[key].Instence is null)
                {
                    // 获取所有的构造函数
                    ConstructorInfo[] cis = _instenceDic[key].ObjectType.GetConstructors();
                    // 获取所有的参数
                    ParameterInfo[] pis = cis[0].GetParameters();
                    // 创建args 参数列表
                    List<object> objects = new List<object>();
                    foreach (ParameterInfo pi in pis)
                    {
                        string paramTypeKey = pi.ParameterType.FullName!;
                        if (_instenceDic.ContainsKey(paramTypeKey!))
                        {
                            if (_instenceDic[paramTypeKey].Instence is null)
                                _instenceDic[paramTypeKey].Instence = Activator.CreateInstance(_instenceDic[paramTypeKey].ObjectType)!;
                            objects.Add(_instenceDic[paramTypeKey].Instence);
                        }
                        else
                            objects.Add(null!);
                    }
                    // 实例化对象
                    var obj = Activator.CreateInstance(_instenceDic[key].ObjectType, objects.ToArray());
                    _instenceDic[key].Instence = obj!;
                }
                return (T)_instenceDic[key].Instence;
            }
            else
                return default(T)!;
        }
    }

    // 单例的初始化对象
    class InstenceModel
    {
        public Type ObjectType { get; set; } // 类型
        public object Instence { get; set; } // 初始化的内容 如果存在证明已经初始化
    }
}

使用:和simpleIoc 使用方法一样:

public class ViewModelCenter
{
    // 自定义IOC容器
    XiaohaiIoc _xiaohaiIoc = XiaohaiIoc.Default;
    public ViewModelCenter()
    {
        // 注册一个Ioc实例
        _xiaohaiIoc.Register<MainViewModel>();

        var model = MainWin;
        MainWin.Value = "ABC";
        var model1 = MainWin;
    }

    public MainViewModel MainWin { get => _xiaohaiIoc.Resolve<MainViewModel>(); }
}

在app.xaml中调用是一样的,在页面中数据绑定也是一样的。

结合IoC模式下的资源释放问题

MainViewModel代码:

 public override void Cleanup()
 {
     base.Cleanup();
 }

ViewModelCenter代码:

参数T 必须继承于ViewModelBase

public static void Cleanup<T>() where T : ViewModelBase
{
    _xiaohaiIoc.Resolve<T>().Cleanup();
}

MainWindow.xaml.cs代码:

 protected override void OnClosed(EventArgs e)
 {
     base.OnClosed(e);

     // 拿到Center 中对应的VM
     ViewModelCenter.Cleanup<MainViewModel>();
 }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2049959.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++ //练习 17.17 更新你的程序,令它查找输入序列中所有违反“ei“语法规则的单词。

C Primer&#xff08;第5版&#xff09; 练习 17.17 练习 17.17 更新你的程序&#xff0c;令它查找输入序列中所有违反"ei"语法规则的单词。 环境&#xff1a;Linux Ubuntu&#xff08;云服务器&#xff09; 工具&#xff1a;vim 代码块&#xff1a; /**********…

定制开发AI智能名片O2O商城小程序:基于限量策略与个性化追求的营销创新

摘要:随着科技的飞速发展和消费者需求的日益多元化&#xff0c;传统商业模式正经历着前所未有的变革。在数字化转型的大潮中&#xff0c;定制开发AI智能名片O2O商城小程序作为一种新兴的商业模式&#xff0c;凭借其独特的个性化定制能力、高效的线上线下融合&#xff08;O2O&am…

居住证申报系统小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;群众用户管理&#xff0c;警方管理&#xff0c;居住证登记管理&#xff0c;回执单管理&#xff0c;领证信息管理&#xff0c;公告栏管理&#xff0c;系统管理 微信端账号功能包括&#xff1a;系统首页…

MySQL数据库专栏(四)数据库操作

1、创建数据库 create database if not exists [数据库名称] character set [字符集] COLLATE [排序规则]; 例如&#xff1a;create database if not exists db_demo character set utf8mb4 COLLATE utf8mb4_general_ci; if not exists&#xff1a;判断数据库是否存在&#x…

Ubuntu20, Windows10 双系统安装

1. 制作启动盘 1.1 下载 Ubuntu 系统镜像 ISO 文件 从 Ubuntu 官网下载 (https://cn.ubuntu.com/download/desktop)。官网访问慢的&#xff0c;从国内镜像点下。 1.2 烧录 Ubuntu ISO 镜像 下载 Rufus&#xff1a;从Rufus官网下载 Rufus 工具。 插入U 盘&#xff1a;将U盘插…

详解语义安全(semantically secure)

目录 一. 引入 二. 密文与明文 2.1 通俗性理解 2.2 定理 2.3 定理理解 三. 语义安全的第一个版本 3.1 基本理解 3.2 定理 3.3 定理理解 四. 语义安全的第二个版本 4.1 直观解释 4.2 小结 一. 引入 密码学中安全加密要求&#xff1a;敌手&#xff08;adversary&…

“百板齐发“ — 一个拥有上百个独特看板的代码

精选100套AXURE可视化数据大屏看板 产品经理高效工具 高保真原型模板 赋能智慧城市 元件库 AXURE9.0版本&#xff0c;所有页面均可编辑&#xff0c;部分地图与实现放大缩小&#xff0c;拖拉拽的功能。 01.水质情况实时监测预警系统 02.全国停车云实时数据监测系统 03.中国移…

【系统分析师】-综合知识-补充知识

1、在软件设计中&#xff0c;通常由着眼于“宏观的”软件架构开始&#xff0c;由着眼于“微观的”构件模块结束。 即测试应该从“微观”开始&#xff0c;逐步转向“宏观”。 2、数据备份是信息系统运行管理时保护数据的重要措施。增量备份可针对上次任何一种备份进行&#xf…

海康VisionMaster使用学习笔记7-Group模块

Group模块的使用 1. 添加图像源&#xff0c;导入图片 2. 添加快速匹配 对匹配框区域进行顶点检测 并循环10次(匹配框个数 从而检测出所有顶点)。 3. 添加Group工具 拖一个Group模块 点击设置 输入设置 添加图像源输入数据 添加快速匹配的匹配框 4. 双击Group工具块进入 添加…

网络原理知识总结

一、网络模型 1.1 osi七层参考模型 物理层&#xff1a;连接通信链路、传输比特流数据链路层&#xff1a;数据封装成帧&#xff0c;在节点与节点间实现可靠物理地址寻址&#xff0c;进行差错校验、流量控制网络层&#xff1a;逻辑地址寻址&#xff0c;路由选择 IP(IPV4IPV6) I…

Oracle start with connect by prior 递归查询

基本语法 select … from tablename where 条件1 start with 条件2 connect by 条件3(PRIOR);条件1&#xff1a;相当于基本的筛选数据 条件2&#xff1a;递归查询起始条件 条件3&#xff1a;连接条件&#xff0c;其中用PRIOR表示上一条记录的结果作为本次查询的条件&#xff0…

后端开发刷题 | 二叉树的前序遍历

描述 给你二叉树的根节点 root &#xff0c;返回它节点值的 前序 遍历。 数据范围&#xff1a;二叉树的节点数量满足 1≤n≤100 &#xff0c;二叉树节点的值满足 1≤val≤100&#xff0c;树的各节点的值各不相同 示例 1&#xff1a; 示例1 输入&#xff1a; {1,#,2,3} 返…

攻击实现摄像头、gvm、openvas安装

网络安全 前言1、kali 发现主机2、[mac地址](https://mac.bmcx.com/#google_vignette)查询3、openvas 安装openvas使用1、添加主机目标2、新建扫描任务3、开始扫描4、查看扫描信息。如果有cve那说明可用 前言 全国网络安全标准化技术委员会&#xff1a;https://www.tc260.org.…

【hot100篇-python刷题记录】【移动零】

R5-双指针 要用双指针来实现&#xff0c;想到一个办法&#xff0c;左右两边双指针&#xff0c;当左边指针找到0就和右指针交换值&#xff0c;要减少操作次数的话&#xff0c;就顺便判断一下右指针是否为0即可&#xff0c;最后肯定是双指针碰撞的。 不对&#xff0c;不能交换值…

普通人如何让AI应用于我们的办公?

最强小说推文——AI视频生成&#xff1a;小说文案智能分镜智能识别角色和场景批量Ai绘图自动配音添加音乐一键合成视频百万播放量https://aitools.jurilu.com/ 当你学会用好AI&#xff0c;真的可以帮助你提高工作效率&#xff0c;把更多的时间放在摸鱼上&#xff01; 想要AI应用…

Emacs25.x版本之重要特性及用法实例(一百五十八)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 新书发布&#xff1a;《Android系统多媒体进阶实战》&#x1f680; 优质专栏&#xff1a; Audio工程师进阶系列…

探索Jinja2的神秘力量:Python模板引擎的魔法之旅

文章目录 探索Jinja2的神秘力量&#xff1a;Python模板引擎的魔法之旅1. 背景&#xff1a;为何选择Jinja2&#xff1f;2. 什么是Jinja2&#xff1f;3. 安装Jinja2&#xff1a;一键启程4. 基础用法&#xff1a;Jinja2的五大法宝5. 实战演练&#xff1a;Jinja2在场景中的应用6. 常…

xssnote

XSS漏洞: 文章目录 XSS漏洞:反射型&#xff1a;第一个例子&#xff1a; 实体&#xff0c;url&#xff0c;和js的Unicode编码img——重要标签浏览器解析机制&#xff1a;容纳字符实体&#xff1a;字符引用&#xff1a;RCDATA状态中的字符引用&#xff1a; URL解析&#xff1a;解…

前端css 动画过渡类型以及不同写法

动画过渡简写和复合写法 拆开写 transition-property: height background; 单独设置宽高或者all transition-duration: 2s; 运动时间 transition-timing-function: linear; 不同速度类型 transition-delay: 5s; 延迟时间 <!DOCTYPE h…

相似度计算方法-编辑距离 (Edit Distance)

定义 编辑距离&#xff08;Edit Distance&#xff09;&#xff0c;也称为Levenshtein距离&#xff0c;是一种衡量两个字符串相似度的方法。它定义为从一个字符串转换为另一个字符串所需的最少单字符编辑操作次数&#xff0c;这些操作包括插入、删除或替换一个字符。 计算方法 …