首页 > 其他分享 >PrismMVVM功能实现(通知、命令)

PrismMVVM功能实现(通知、命令)

时间:2024-08-02 17:55:28浏览次数:10  
标签:CompositeCommand DelegateCommand get 通知 视图 PrismMVVM 命令 public

常见的MVVM框架,基本围绕ICommand、INotifyPropertyChanged的封装实现绑定、通知等功能;而对于不同框架,在实现相同功能上,只是表现的形式有所不同,下图列举几种常见框架的功能区别:

功能\框架 Prism MVVMLight Micorsoft.Tookit.Mvvm
通知 BindableBase ViewModelBase ObservableObject
命令 DelegateCommand RelayCommand Async/RelayCommand 
事件聚合器 IEventAggregator IMessenger IMessenger
模块化 × ×
容器 × ×
依赖注入 × ×
导航 × ×
对话服务 × ×

通知(BindableBase)

BindableBase 主要实现 INotifyPropertyChanged 接口,用于监听属性更改时提供通知,实现方式为在属性 SET 中添加 RaisePropertyChanged() 方法,具体过程如下:

基础的通知属性的三种方式

// 基础的通知属性
private string _value;

public string Value
{
    get { return _value; }
    set
    {
        // 第一种方式
        SetProperty<string>(ref _value, value);

        // 第二种方式
        _value = value;
        this.RaisePropertyChanged(nameof(Value));

        // 第三种方式
        _value = value;
        this.OnPropertyChanged(new System.ComponentModel.PropertyChangedEventArgs(nameof(Value)));
    }
}

运行效果如下:

单一命令(DelegateCommand)

ViewModel 可以通过将命令接口实现为命令对象 (实现 ICommand 接口的对象)。视图与命令的交互以声明的方式定义,而无需在视图的代码隐藏文件中使用复杂的事件处理代码。实现 ICommand 接口很简单,Prism 提供了 DelegateCommand 此接口的实现,您可以在应用程序中轻松使用。

创建委托命令 

Prism DelegateCommand 类封装了两个委托,每个委托都引用了在 ViewModel 类中实现的方法。它通过调用这些委托来实现 ICommand 接口Execute 和方法。 CanExecute 您在 DelegateCommand 类构造函数中指定 ViewModel 方法的委托。例如,以下代码示例显示了如何DelegateCommand 通过指定 OnSubmit 和 CanSubmit ViewModel 方法的委托来构造表示提交命令的实例。然后,该命令通过一个只读属性暴露给视图,该属性返回对 DelegateCommand . 

//无参、仅Excute构造方式
public class ArticleViewModel
{
    public DelegateCommand SubmitCommand { get; private set; }
    public ArticleViewModel()
    {
    SubmitCommand = new DelegateCommand(Submit);
    }
    void Submit()
    {
        //执行方法
    }
}
//有参、Execute和CanExecut同时构造方式
public class ArticleViewModel
{
    public DelegateCommand SubmitCommand { get; private set; }
    public ArticleViewModel()
    {
    SubmitCommand = new DelegateCommand<object>(Submit, CanSubmit);
    }
    void Submit(object parameter)
    {
    //执行方法
    }
    bool CanSubmit(object parameter)
    {
    return true;
    }
}
//无参、Execute和CanExecut同时构造方式
public class ArticleViewModel
{
    public DelegateCommand SubmitCommand { get; private set; }
    public ArticleViewModel()
    {
    SubmitCommand = new DelegateCommand(Submit, CanSubmit);
    }
    void Submit()
    {
    //implement logic
    }
    bool CanSubmit()
    {
    return true;
    }
}

从视图调用命令

使用 CommandParameter 属性定义命令参数。定义的参数类型在 DelegateCommand 泛型声明中指定。当用户与该控件交互时,该控件将自 动调用目标命令,并且命令参数(如果提供)将作为参数传递给命令的 Execute 方法。 

<Button Command="{Binding SubmitCommand}" CommandParameter="OrderId"/>

事件转命令

侦听Grid的MouseLeftButtonDown事件,并使用Command绑定

<Window x:Class="Zhaoxi.MvvmBaseObject.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:Zhaoxi.MvvmBaseObject"
        xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
        xmlns:p="http://prismlibrary.com/"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid Background="Transparent">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="MouseLeftButtonDown">
                <p:InvokeCommandAction Command="{Binding ButtonCommand}"/>
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </Grid>
</Window>
public DelegateCommand<object> ButtonCommand { get; set; }


public MainViewModel()
{
    ButtonCommand = new DelegateCommand<object>(arg =>
    {

    });
}

不设置p:InvokeCommandAction的TriggerParameterPath属性,传递参数是{System.Windows.Input.MouseButtonEventArgs}

设置TriggerParameterPath参数会传递所设置的参数,或者传递{System.Windows.Input.MouseButtonEventArgs}中具体的属性比如ButtonState

    <Grid Background="Transparent">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="MouseLeftButtonDown">
                <p:InvokeCommandAction Command="{Binding ButtonCommand}" TriggerParameterPath="ButtonState"/>
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </Grid>

使用WPF原生的InvokeCommandAction默认不传递参数,需要设置PassEventArgsToCommand="True"可以传递{System.Windows.Input.MouseButtonEventArgs}

    <Grid Background="Transparent">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="MouseLeftButtonDown">
                <i:InvokeCommandAction Command="{Binding ButtonCommand}" PassEventArgsToCommand="True"/>
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </Grid>

创建异步委托命令

在当今的 async / await 使用中,在委托中调用异步方法 Execute 是非常普遍的要求。每个人的第一直觉是他们需要一个 AsyncCommand ,但这种假设是错误的。 ICommand 本质上是同步的, Execute 并且 CanExecute 委托应该被视为事件。这意味着这 async void 是用于命令的完全有效的语法。有两种方法可以将异步方法与 DelegateCommand 结合使用:

方式1 

public class ArticleViewModel
{
    public DelegateCommand SubmitCommand { get; private set; }
    public ArticleViewModel()
    {
    SubmitCommand = new DelegateCommand(Submit);
    }
    async void Submit()
    {
    await SomeAsyncMethod();
    }
}

方式2

public class ArticleViewModel
{
    public DelegateCommand SubmitCommand { get; private set; }
    public ArticleViewModel()
    {
    SubmitCommand = new DelegateCommand(async ()=> await Submit());
    }
    Task Submit()
    {
    return SomeAsyncMethod();
    }
}

复合命令(CompositeCommand) 

在许多情况下,视图模型定义的命令将绑定到关联视图中的控件,以便用户可以直接从视图中调用该命令。但是,在某些情况下,您可能希望能够从应用程序 UI 的父视图中的控件调用一个或多个视图模型上的命令。

Prism 通过 CompositeCommand 类支持这种情况 。

该类 CompositeCommand 表示由多个子命令组成的命令。当调用复合命令时,依次调用它的每个子命令。在您需要将一组命令表示为 UI 中的单个命令或您希望调用多个命令来实现逻辑命令的情况下,它很有用。

该类 CompositeCommand 维护一个子命令( DelegateCommand 实例)列表。类的 Execute 方法 CompositeCommand 简单地依次调用Execute 每个子命令的方法。该 CanExecute 方法类似地调用 CanExecute 每个子命令的方法,但如果任何子命令无法执行,该 CanExecute 方法将返回 false 。也就是说,默认情况下,a CompositeCommand 只有在所有子命令都可以执行时才能执行。

创建复合命令

复合命令绑定到视图

在视图中,将“CompositeButton”按钮与到 TestCompositeCommand 命令绑定。

运行结果如下:

不同页面绑定同一复合命令

跨页面绑定需要全局单例复合命令,可以注册单例复合命令,在注入到各模块中

MainWindow

 <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="30"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <StackPanel Orientation="Horizontal">
            <Button Content="显示页面" Command="{Binding ShowPageCommand}"/>
            <Button Content="全部保存" Command="{Binding AllSaveCommand}"/>
        </StackPanel>

        <UniformGrid Columns="2" Grid.Row="1">
            <ContentControl p:RegionManager.RegionName="Region1"/>
            <ContentControl p:RegionManager.RegionName="Region2"/>
        </UniformGrid>
    </Grid>

ViewA

    <Grid>
        <Button Content="A保存" Command="{Binding SaveCommand}"/>
    </Grid>

ViewB

    <Grid>
        <Button Content="B保存" Command="{Binding SaveCommand}"/>
    </Grid>

注册页面和单例复合命令

public class Startup : PrismBootstrapper
{
    protected override DependencyObject CreateShell()
    {
        return Container.Resolve<PrismRegion.Composite.MainWindow>();
    }

    protected override void RegisterTypes(IContainerRegistry containerRegistry)
    {
        containerRegistry.RegisterForNavigation<PrismRegion.Composite.ViewA>();
        containerRegistry.RegisterForNavigation<PrismRegion.Composite.ViewB>();
        //注册单例命令
        containerRegistry.RegisterSingleton<CompositeCommand>();
    }
}

MainWindowViewModel

注入CompositeCommand拿到全局复合命令,并关联实例AllSaveCommand

public class MainWindowViewModel
{
    public CompositeCommand AllSaveCommand { get; set; }

    public DelegateCommand ShowPageCommand { get; set; }

    public MainWindowViewModel(IRegionManager regionManager,
        CompositeCommand composite)
    {
        ShowPageCommand = new DelegateCommand(() =>
        {
            regionManager.RequestNavigate("Region1", "ViewA");
            regionManager.RequestNavigate("Region2", "ViewB");
        });


        AllSaveCommand = composite;
        //AllSaveCommand.RegisterCommand(ShowPageCommand);
    }
}

ViewAViewModel

注入CompositeCommand拿到全局复合命令,将SaveCommand加入到复合命令

public class ViewAViewModel
{
    public DelegateCommand SaveCommand { get; set; }

    public ViewAViewModel(CompositeCommand composite)
    {
        SaveCommand = new DelegateCommand(() =>
        {


        });
        composite.RegisterCommand(SaveCommand);
    }
}

ViewBViewModel

注入CompositeCommand拿到全局复合命令,将SaveCommand加入到复合命令

public class ViewBViewModel
{
    public DelegateCommand SaveCommand { get; set; }

    public ViewBViewModel(CompositeCommand composite)
    {
        SaveCommand = new DelegateCommand(() =>
        {


        });
        // 这里有前后关系,很重要
        composite.RegisterCommand(SaveCommand);
        //composite.UnregisterCommand(SaveCommand);
    }
}

运行后按钮先为黑色,因为还没ViewA和ViewB没有初始化,复合命令为空

点击显示页面后,ViewA和ViewB的命令加入到复合命令后按钮可以点击

取消注册命令

如前面的示例所示,子命令是使用该 TestCompositeCommand.RegisterCommand 方法注册的。但是,当您不再希望响应 TestCompositeCommand或者您正在销毁 View/ViewModel 以进行垃圾回收时,您应该使用该 TestCompositeCommand.UnregisterCommand 方法取消注册子命令。

/// 取消命令注册例子
public void Destroy()
{
    TestCompositeCommand.UnregisterCommand(TestCommand1);
}

通过依赖注入、静态类来实现 CompositeCommand 全局可用/绑定等用法,请查阅Prism官方文档。

来源:https://www.cnblogs.com/ZHIZRL/p/17675034.html

 

标签:CompositeCommand,DelegateCommand,get,通知,视图,PrismMVVM,命令,public
From: https://www.cnblogs.com/ywtssydm/p/18339304

相关文章

  • telegraf 常用命令总结
    Telegraf是一个灵活的服务器代理,用于收集和报告指标。它支持插件驱动,这意味着你可以根据需要添加或修改功能。1.使用telegraf--help查看telegraf提供的相关命令和参数使用telegraf--help可以查看telegraf提供的相关命令和参数,具体如下:telegraf--helpTelegraf,The......
  • 输入“func start”命令时会找到并运行函数,但在命令 func azurepublish 时无法识别函
    本质上我有一个正在尝试部署到天蓝色的功能。当我输入“funcstart”时,该函数在本地运行,并且可以将发布请求发送给它。然而,当我尝试将函数部署到azure时,部署总是成功,但函数本身永远不会推送到azure。即远程构建成功![2024-07-26T15:17:11.932Z]同步触发器...函数位于:.........
  • windows 命令行 pip 安装报错
    pipinstalltkWARNING:Retrying(Retry(total=4,connect=None,read=None,redirect=None,status=None))afterconnectionbrokenby'ProxyError('Cannotconnecttoproxy.',OSError(0,'Error'))':/simple/tk/WARNING:Retrying(R......
  • influxDB的常用命令
    目录1.查看数据库命令2.进入某数据库命令3.创建表的命令 (host和region字段是必须的) 4.显示所有的表命令5.删除表6.查询表数据 7.显示数据库用户8.创建用户9.创建管理员用户 10.修改密码(密码用单引号括住,不要用双引号)11.分配数据库访问权限(授权用户数据......
  • Linux - 查看CPU使用率命令mpstat
    简介想在imx6q上定时查看CPU使用率,发现命令mpstat可以直接使用,不需要额外安装 使用mpstat的基本用法mpstat的全称为MultiprocessorStatistics,是一款常用的多核CPU性能分析工具,用来实时查询每个CPU的性能指标,以及所有CPU的平均指标。这个命令Linux缺省没有安装,它是Linux性......
  • 在cmd/powershell中使用java/javac -cp/--class-path命令链接多个jar包
    ​ 之前使用ide,习惯了傻瓜式一键运行java文件,对于java虚拟机以及java指令了解的很少,最近重温java,在使用windows中的cmd来运行java项目时,遇到了一点问题,相同的指令在cmd中能够运行,在powershell中不能正确运行,在国内网站上搜索无果后,果断去国外,在stackoverflow上找到解决办法。​ ......
  • Linux基本知识与基础命令
    一、简易历史linux最初由林纳斯·本纳第克特·托瓦兹(LinusBenedictTorvalds,1969年~)于1991年第一次向外公布,其logo是一只被成为Tux的企鹅(不是qq那只)操作系统,英语OperatingSystem简称为OS。说道操作系统就需要先讲一讲Unix,UNIX操作系统,是一个强大的多用户、多任务操作系统,支......
  • 【反向Shell命令】集合
    ❝本指南提供了多种方法来建立反向Shell,包括使用加密和明文方式,适用于不同的场景和需求。通过这些技术,安全专家和合法授权的渗透测试者可以有效地控制远程系统,进行安全测试和漏洞评估。gs-netcat提供加密的反向Shell,支持文件传输和管理员登录警报。Bash和cURL方......
  • Linux学习笔记8(Find命令进阶学习)
    目录通过所有者来查找1.指定所属的用户2.指定所属的组通过权限来查找1.指定精确的权限查找2.指定所有者(用户、组、其他人)至少有一个拥有此权限即可3.指定文件最低权限查找,即大于等于4.查找文件不是指定的权限(取反)5.查找所有只读的文件6.查找所有可执行文件......
  • Java的编译和运行命令
    Java的编译和运行命令Java是一种编译型语言,但与传统的编译型语言(如C或C++)不同,Java的编译和运行过程涉及到几个关键步骤,这些步骤使得Java能够实现其“一次编写,到处运行”(WriteOnce,RunAnywhere,WORA)的特性。以下是Java编译和运行的基本原理:编写源代码:开发者使用文本编辑器......