添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
体贴的南瓜  ·  memory - cudaMemcpy ...·  1 年前    · 
  • 使用NuGet即可下载到最新免费的MVVMLight,安装之后,会有以下几个DLL被项目引用:
    在这里插入图片描述

其中还依赖了一个微软的DLL——Microsoft.Practices.ServiceLocation.dll。

  • 在使用过程中,**可能遇到的问题:**就是可能是由于MvvmLight没有及时更新,如果将图中的CommonServiceLocator升级到最新的2.x版本之后,它所依赖的ServiceLication的名称空间变为了CommonServiceLocator,导致安装MvvmLight之后自动生成的代码就出现了错误, 如果你使用了最新版本,那么就需要手动修改一下这个名称空间
    在这里插入图片描述

  • 安装完成MvvmLight之后,系统会自动生成一个ViewModel文件夹以及MainViewModel和ViewModelLocator两个文件,并将ViewModelLocator添加到了全局资源App.xaml中:

<Application x:Class="MvvmLightDemo.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:MvvmLightDemo" StartupUri="MainWindow.xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008" d1p1:Ignorable="d"
            xmlns:d1p1="http://schemas.openxmlformats.org/markup-compatibility/2006">
  <Application.Resources>
    <ResourceDictionary>
      <vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" xmlns:vm="clr-namespace:MvvmLightDemo.ViewModel" />
    </ResourceDictionary>
  </Application.Resources>
</Application>

重点类型一: ViewModelLocator

这个类型有什么作用,要把它放到全局资源中?

  • 在View层,即XAML文件中,不必直接引用ViewModel类型了,通过Locator中的Register进行关联
    • 所有的View都可以到Locator中找到自己需要的VM层,这个Locator相当于一个索引器
    • Locator层返回的VM层是单例形式的,避免了由于代码问题导致的内存泄漏
/// <summary>
/// This class contains static references to all the view models in the
/// application and provides an entry point for the bindings.
/// 这个类型的用处就是包含了所有的View和ViewModel之间的关联,使得View和ViewModel不再直接引用;
/// </summary>
public class ViewModelLocator
    /// <summary>
    /// Initializes a new instance of the ViewModelLocator class.
    /// </summary>
    public ViewModelLocator()
        ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
        if (ViewModelBase.IsInDesignModeStatic)
            // 在Visual Studio中设计预览Xaml文件的时候,在这里注册会起作用;
            SimpleIoc.Default.Register<MainViewModel>();
            // 在运行时,在这里注册会起作用;
            SimpleIoc.Default.Register<MainViewModel>();
        // 更多的时候,默认在这里注册就可以了;
        SimpleIoc.Default.Register<MainViewModel>();
    /// <summary>
    /// 这里对应的是View中DataContext需要的依赖属性;
    /// 就是这个Main属性,关联起了View和ViewModel;
    /// DataContext="{Binding Source={StaticResource Locator}, Path=Main}
    /// </summary>
    public MainViewModel Main
            return ServiceLocator.Current.GetInstance<MainViewModel>();
    public static void Cleanup()
        // TODO Clear the ViewModels

重点类型二:ViewModelBase

它继承自父类ObservableObject,实现了INotifyPropertyChanged和ICleanup,以实现:

  • 当对象的属性发生变化的时候,会通知View层更新它的显示
  • 在Page切换、标签页关闭等场景中,使用Clearup以及-=event释放不再需要的资源
使用依赖属性:

在使用的过程中,需要我们调用ViewModelBase为我们提供的Set函数在属性的Set当中调用,即可实现通知View层的效果:

using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using System;
public class MainViewModel : ViewModelBase
    private string m_LabelShow;
    public string Label1Show
        get { return m_LabelShow; }
        // MvvmLight实现的Set方法,好处就是不用自己实现RaisePropertyChanged函数了;
        set { Set(ref m_LabelShow, value); }
    /// <summary>
    /// Initializes a new instance of the MainViewModel class.
    /// </summary>
    public MainViewModel()
        Label1Show = "ShowOne";

至于MvvmLight的实现原理,以下代码可以表明MvvmLight到底做了些什么:

  • 它帮助我们实现了RaisePropertyChanged方法
  • 在属性值发生变化的时候,就可以发出通知
/// <summary>
/// 写一个一个轻量级MVVM框架,以帮助理解MVVM到底是什么;
/// INotifyPropertyChanged接口实现了当属性发生变化的时候,可以及时发出通知
/// </summary>
public class MvvmBase : INotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;
    /// <summary>
    /// 属性发生改变时调用该方法发出通知;
    /// </summary>
    /// <param name="propertyName">属性名称</param>
    public void RaisePropertyChanged(string propertyName)
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    protected virtual void SetAndNotifyIfChanged<T>(string propertyName, ref T oldValue, T newValue)
        if (oldValue == null && newValue == null) return;
        if (oldValue != null && oldValue.Equals(newValue)) return;
        if (newValue != null && newValue.Equals(oldValue)) return;
        oldValue = newValue;
        RaisePropertyChanged(propertyName);
在依赖属性的基础上使用依赖命令RelayCommand<>

RelayCommand翻译过来就是“依赖命令”,相对于依赖属性,该类型主要作用就是让ViewModel层的类型具有处理依赖命令的能力。如果一个控件中包含了一个Icommand接口,那么就可以在MvvmLight架构下的VM层使用RelayCommand对依赖命令进行实现了

以下这个例子是利用RelayCommand实现一个前进后退按钮,可以导航控制Page页:

利用MvvmLight实现的优势就是:

  • 前端XMAL编写和后端ViewModel编写能够完全解耦和,互不干扰
  • ViewModel端直接控制自己的所有属性

View端:

<Window x:Class="MvvmLightDemo.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:MvvmLightDemo"
        xmlns:vm="clr-namespace:MvvmLightDemo.ViewModel"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800"
        DataContext="{Binding Source={StaticResource Locator}, Path=Main}">
        <Grid.RowDefinitions>
            <RowDefinition Height="10*"></RowDefinition>
            <RowDefinition Height="90*"></RowDefinition>
        </Grid.RowDefinitions>
        <!-- 依赖命令的Binding -->
        <StackPanel Orientation="Horizontal" Grid.Row="0" >
            <Button Command="{Binding NavToPrePage}">Nav To PrePage</Button>
            <Button Command="{Binding NavToNextPage}">Nav To NextPage</Button>
        </StackPanel>
        <!-- 依赖属性的Binding -->
        <Frame Content="{Binding MainWindowFrame}" Grid.Row="1" NavigationUIVisibility="Hidden"></Frame>
    </Grid>
</Window>

ViewModel端:

public class MainViewModel : ViewModelBase
    /// <summary>
    /// 导航到下一页面按钮的依赖命令;
    /// </summary>
    public RelayCommand NavToNextPage { get; set; }
    /// <summary>
    /// 导航到上一页面按钮的依赖命令;
    /// </summary>
    public RelayCommand NavToPrePage { get; set; }
    /// <summary>
    /// 主页Frame;
    /// </summary>
    private Frame m_MainWindowFrame;
    public Frame MainWindowFrame
        get { return m_MainWindowFrame; }
        set { Set(ref m_MainWindowFrame, value); }
    /// <summary>
    /// 主标签页;
    /// </summary>
    private Page m_MPage;
    public Page MPage
        get { return m_MPage; }
        set { Set(ref m_MPage, value); }
    /// <summary>
    /// 附标签页;
    /// </summary>
    private Page m_AttachPage;
    public Page AttachPage
        get { return m_AttachPage; }
        set { Set(ref m_AttachPage, value); }
    /// <summary>
    /// Initializes a new instance of the MainViewModel class.
    /// </summary>
    public MainViewModel()
        NavToNextPage = new RelayCommand(NavNextPage);   // 导航到下一个Page页;
        NavToPrePage = new RelayCommand(NavPrePage);
        MPage = new MainPage();
        AttachPage = new PageTwo();
        MainWindowFrame = new Frame();
        MainWindowFrame.NavigationUIVisibility = System.Windows.Navigation.NavigationUIVisibility.Hidden;
        MainWindowFrame.Content = MPage;
    /// <summary>
    /// 处理点击下一页;
    /// </summary>
    private void NavNextPage()
        MainWindowFrame.Content = AttachPage;
    /// <summary>
    /// 处理点击上一页;
    /// </summary>
    private void NavPrePage()
        MainWindowFrame.Content = MPage;

源代码可参见:https://github.com/visiontrail/CSharpKnowledge 在工程MvvmLightDemo工程当中,使用VS2015/VS2017编译

GetInstance(Type, string) 这是从容器检索单个实例的核心方法。 此方法不得返回null。 它必须返回一个实现请求类型的实例,或者抛出一个ActivationException。 不允许其他任何异常类型(除了诸如ThreadAbortException之类的常规CLR规则外)。 该实现应设计为期望字符串key参数为null,并且必须将此解释为获取所请求类型的“默认”实例的请求。 “默认”的含义取决于基础容器及其配置方式。 长度为0的字符串被认为不同于null,实现者可以自由选择长度为0的字符串作为键的含义。 GetAllInstances(Type) 这是从容器检索多个实例的核心方法。 如果容器不包含所请求类型的实例,则此方法务必返回长度为0 MVVM Light是WPF的一个mvvm框架,目前已经停止维护,适用于Net framework版本下的WPF程序,如果要在net5或者更新的net版本使用,可以使用新的CommunityToolkit.Mvvm包,它是 .NET 社区工具包的一部分,用法和MvvmLight类似。 WPF MVVM解析 介绍:下面界面是一个简易的加法计算器,其包括三个数据属性(Value1,Value2,Sum)和两个命令属性(Save,Calculator),使用MVVM模式实现方法如下: 第一步:创建一个WPF项目,UI代码如下(其的数据和命令绑定其实是后续添加的): <Window x:Class="WPF_MVVM_Demo.MainWindow" xml... 本篇我们着重介绍ViewModelBase,演示Set和RaisePropertyChanged方法的使用,以及就Cleanup方法释放资源展开讨论。 ICleanup 接口。 实现该接口的ViewModel需要在Cleanup方法里释放资源,特别是-= event ObservableObject 该类实现了INotifyPropertyChanged接口,定义了一个可通知的对象基类, 小弟在一个TabItem里放了一个注册了消息的控件,每次在关闭标签页后再重新打开都会在一个属性的RaisePropertyChanged里报错,开始先是以为是初始化的错误,又以为是用了Ni控件的原因,折腾了两三天后还是找不出问题,只好先放弃了。 没想到今天在做父子窗口数据传递的时候,在网上搜到有文章说子窗口关闭的时候必须要Cleanup,反注册掉所有的消息,我一下子想起了这个问题。果断在控件的c MvvmLight: ICleanup 实现了这个接口的ViewModel当不需要使用时,可以在Cleanup方法去释放资源 ObservableObject该类实现了INotifyPropertyChanged接口,定义了一个可通知的对象基类,供ViewModelBase继承 , ViewModelBase属于主体库,继承自Observabl 一、MVVM 和 MVVMLight介绍 MVVM是Model-View-ViewModel的简写。类似于目前比较流行的MVC、MVP设计模式,主要目的是为了分离视图(View)和模型(Model)的耦合。 它是一种极度优秀的设计模式,但并非框架级别的东西,由MVP(Model-View-Presenter)模式与WPF结合的应用方式时发展演变过来的一种新型架构。 立足于原有MVP框架并且把... protected virtual void RaisePropertyChanging<T>(Expression<Func<T>> propertyExpression); protected bool Set<T>(Expression<Func<T>> propertyExpression,...   MvvmLight是比较流行的MVVM框架,相对较为简单易用。可能正因为简单,对应的帮助文档不多,对初学者就不够友好了。这里会用几篇随笔,就个人对MvvmLight使用经验,来做一个入门的介绍。   第一步我们先找到并下载MvvmLight的最新版,我个人倾向使用NuGet。这里顺便吐槽一下,MvvmLight貌似并未在Github上创建项目,虽然作者对MS深深的爱让我感动,不过也不要排... wpf的精华就是mvvm,viewmodel与view以及db.cs数据库操作类的关系,使得mianwondow几乎不用写什么代码,逻辑都放在viewmodel里,db里存放一些基础数据操作方法。内附源码链接。 先展示一下界面: 新增以及修改界面 先展示一下解决方案,如下图,db文件夹下存放的mydb.cs是数据库基本操作,model下的student.cs是实体类,view文件夹下是视图(界面)文件,viewmodel文件夹下的mianviewmodel.cs是vm文... 三个控件同时绑定了一个变量(点击按钮通过MessageBox显示变量值),通过NuGet下载MVVM Light: MainViewModel类代码: using GalaSoft.MvvmLight; using GalaSoft.MvvmLight.Command; namespace WPF0416.ViewModel pub... 首先,在你的自定义控件类 (示例:以上代码简化了官方方法的流程,以便你不用再去额外输入不必要的参数,并提前对 sender 进行类型转换。此后,添加一个属性只需要添加以下代码即可,相比传统方法看起来会非常直观,非常省事。以上代码,defaultValue 可以为 null,但使用 null 作为默认值必须声明泛型类型。