Prism 行为处理

news/2024/9/29 16:30:41

Prism框架提供了DelegateCommand类型,专门用于进行WPF中的行为处理。

基本使用
一、命令的使用
DelegateCommand(Action executeMethod):DelegateCommand的构造函数,创建DelegateCommand对象。

executeMethod:无参的命令执行函数。
定义命令

public class MainViewModel
{public ICommand BtnCommand => new DelegateCommand(Execute);private void Execute(){//做命令执行业务
    }
}
<Window ......><Window.DataContext><local:MainViewModel/></Window.DataContext><Grid><StackPanel><Button Content="BtnCommand" Command="{Binding BtnCommand}"/></StackPanel></Grid>
</Window>

带参数的命令

Prism框架中,命令的使用跟MVVMToolkit框架是类似的,命令的执行函数可以有参,也可以无参,具体用法如下:

public ICommand BtnCommand => new DelegateCommand<string>(Execute);private async void Execute(string str)
{await Task.Delay(2000);Value = 100;
}

二、命令的状态检查
Prism提供了三种命令状态检查方式

1、方式1:调用RaiseCanExecuteChanged方法
可以向DelegateCommand的构造函数中传入状态检查的委托函数。然后在合适的节点去调用DelegateCommand对象的RaiseCanExecuteChanged方法来执行状态检查函数。

DelegateCommand(Action executeMethod, Func<bool> canExecuteMethod):DelegateCommand的构造函数,创建DelegateCommand对象。

executeMethod:无参的命令执行函数。
canExecuteMethod:命令的状态检查函数。
RaiseCanExecuteChanged():调用DelegateCommand对象的命令状态检查函数(构造时传入的函数)。

定义命令

需要注意以下两点:

RaiseCanExecuteChanged():此方法是DelegateCommand对象的方法,ICommand接口中没有,为了后续方便,创建时直接使用DelegateCommand而不是ICommand类型。
DelegateCommand对象的初始化(new)必须放在所在类型的构造函数中进行,否则调用RaiseCanExecuteChanged函数不起作用。

public class MainViewModel
{private int _value = 10;public int Value{get { return _value; }set { _value = value;//调用命令状态检查函数
            BtnCheckCommand.RaiseCanExecuteChanged();}}//声明属性,但不做初始化,留在构造函数中做public DelegateCommand BtnCheckCommand { get; }private bool CheckCanExecute(){return Value == 100;}private void Execute(){//做命令执行业务
    }public MainViewModel(){//继续命令初始化,只能放在这里做,放在属性中进行初始化的话,调用状态检查函数无效果。BtnCheckCommand = new DelegateCommand(Execute, CheckCanExecute);}
}

2、方式2:使用ObservesProperty监听属性变化
DelegateCommand(Action executeMethod, Func<bool> canExecuteMethod):DelegateCommand的构造函数,创建DelegateCommand对象。

executeMethod:无参的命令执行函数。
canExecuteMethod:命令的状态检查函数。
DelegateCommand ObservesProperty<T>(Expression<Func<T>> propertyExpression):DelegateCommand对象的方法,用于监听指定属性的变化,一旦属性发生变化,就调用构造时传入的状态检查函数。

propertyExpression:一个返回指定监控属性的无参Lambda表达式。
由于调用后就返回监听该属性的DelegateCommand对象,因此可以通过链式调用监听多个属性的变化。

public class MainWindowViewModel : BindableBase
{private int _value1;public int Value1{get { return _value1; }set { SetProperty(ref _value1, value); }}private int _value2;public int Value2{get { return _value2; }set { SetProperty(ref _value2, value); }}private void Execute(){//做命令执行业务
    }public DelegateCommand BtnCheckCommand { get; }private bool CheckCanExecute(){return Value1 + Value2 == 100;}public MainWindowViewModel(){BtnCheckCommand = new DelegateCommand(Execute, CheckCanExecute).ObservesProperty(() => Value1).ObservesProperty(() => Value2);//通过链式结构可以同时监听多个属性,进行组合判断
    }
}

这种方式比第1种方式要更加方便,不用考虑在哪个地方去主动调用命令状态检查函数。

3、方式3:使用ObservesProperty
DelegateCommand ObservesCanExecute(Expression<Func<bool>> canExecuteExpression):DelegateCommand的实例方法,根据传入的Lambda表达式,来检查命令的可执行状态。

canExecuteExpression:一个返回bool类型属性的表达式。
注意

传递给ObservesCanExecute的Lambda表达式中,需要返回bool类型的属性而不是直接的bool值,否则无效。

传递给ObservesCanExecute的Lambda表达式中返回的属性,有两点需要注意:

必须做属性变化通知处理。
在第二次属性变化通知起,才能正确完成命令可执行状态检查,也就是第一次变化通知不会正常完成命令状态检查,需要提前做一下第一次的属性变化。
此属性发生变化时才会触发命令可执行状态检查,因此要在合适的时候去改变属性来触发检查。
命令定义

public class MainViewModel: BindableBase
{private int _value = 10;public int Value{get { return _value; }set{_value = value;//在合适的时机去改变Status属性,触发变化通知,从而调用状态检查Status = !Status;}}public bool status = false;public bool Status{get { return Value == 100; }set {//一定要做属性变化通知,以此来触发状态检查SetProperty(ref status, value); }}private void Execute(){//做命令执行业务
    }public DelegateCommand BtnCheckCommand { get; }public MainViewModel(){//与前两中方式相比,可以不需要传入命令状态检查函数BtnCheckCommand = new DelegateCommand(Execute).ObservesCanExecute(()=> Status);Status = !Status;//要先触发一次Status的属性变化通知,在第二次属性变化通知时才能顺利的检查命令的状态
    }
}

三、异步处理

Prism的异步处理没什么新鲜的,就是正常的使用异步函数,具体如下

public ICommand BtnCommand
{get => new DelegateCommand(Execute);
}private async void Execute()
{await Task.Delay(2000);Value = 100;
}

一、事件触发命令

定义命令

public class MainViewModel: BindableBase
{private int value = 10;public int Value{get { return value; }set {SetProperty(ref this.value, value);    }}public ICommand BtnCommand { get => new DelegateCommand<object>(Execute); }private void Execute(object obj){Value = 100;}}

xaml中绑定命令

注意,这里因为使用了Prism框架的命令,因此在绑定命令时使用了prism:InvokeCommandAction。如果没有使用Prism框架,可以使用i:InvokeCommandAction,也就是Behaviors包自带的。

<Window ......xmlns:i="http://schemas.microsoft.com/xaml/behaviors"xmlns:prism="http://prismlibrary.com/"......><Window.DataContext><local:MainViewModel/></Window.DataContext><Grid><StackPanel><TextBlock Text="{Binding Value}"/><ComboBox SelectedIndex="0"><i:Interaction.Triggers><i:EventTrigger EventName="SelectionChanged"><prism:InvokeCommandAction Command="{Binding BtnCommand}"/></i:EventTrigger></i:Interaction.Triggers><ComboBoxItem Content="item1"/><ComboBoxItem Content="item2"/><ComboBoxItem Content="item3"/><ComboBoxItem Content="item4"/></ComboBox></StackPanel></Grid>
</Window>

注意

默认情况下,上述做法会直接将EventArgs对象作为参数传递给命令执行函数,如果需要进行参数的指定,可以通过prism:InvokeCommandAction元素的TriggerParameterPath属性来将EventArgs中的某个属性成员作为参数传入,或者使用CommandParameter属性,将其他对象作为参数传递给命令执行函数。如果同时使用TriggerParameterPath和CommandParameter属性,则优先传递CommandParameter属性设置的参数。

例如:<prism:InvokeCommandAction Command="{Binding BtnCommand}" TriggerParameterPath="Handled"/>就是将EventArgs对象中的Handled属性作为参数传递给命令执行函数。

二、事件触发方法
在Behaviores包的帮助下,也可以直接让事件来触发指定的方法。

定义执行方法

public class MainWindowViewModel
{public void TextBox_KeyDown(object sender, KeyEventArgs e){if (e.Key == Key.Enter){//输入键
        }}
}

注意,事件处理方法会接收到几个默认的参数,如果不知道是什么参数对象可以通过在控件中自动生成事件方法来参考一下。在本例中可以通过<TextBox …… KeyDown="TextBox_KeyDown">,自动生成TextBox_KeyDown方法来查看接收什么参数。

XAML中使用

注意,这里使用的是b:CallMethodAction,是Behaviors包中提供的对象。

TargetObject:指定事件处理方法所在的对象。

MethodName:事件处理方法的名称。

<Window ......xmlns:b="http://schemas.microsoft.com/xaml/behaviors"><Grid><TextBox Height="30" Width="100"><b:Interaction.Triggers><b:EventTrigger EventName="KeyDown"><b:CallMethodAction TargetObject="{Binding}" MethodName="TextBox_KeyDown"/></b:EventTrigger></b:Interaction.Triggers></TextBox></Grid>
</Window>

复合命令
复合命令是指一个命令可以同时完成多个命令,Prism提供了CompositeCommand类型专门用于实现复合命令。

注册命令

RegisterCommand(ICommand command):CompositeCommand的实例方法,用于注册命令,也就是将指定命令添加到当前复合命令对象中。

UnregisterCommand(ICommand command):CompositeCommand的实例方法,用于取消注册指定命令,即从当前复合命令对象中移除指定命令。

同一个模块(例如要复合的命令全部都在MainWindowViewModel中)的复合命令是很容易实现的,即使不使用CompositeCommand也可以实现。然而在实际开发中,要用到复合命令的情景往往是需要将多个不同模块中的命令集中起来一次性全部调用。这个过程不仅需要使用到CompositeCommand类,还需要借助IOC容器的依赖注入来实现。

<Window x:Class="WpfApp1.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:local="clr-namespace:WpfApp1"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:prism="http://prismlibrary.com/"Title="MainWindow"Width="800"Height="450"prism:ViewModelLocator.AutoWireViewModel="True"mc:Ignorable="d"><Grid><Grid.RowDefinitions><RowDefinition Height="150" /><RowDefinition /></Grid.RowDefinitions><UniformGrid Rows="2"><Button Command="{Binding UnionCommand.Commands}" Content="UnionCommand" /><UniformGrid Columns="2"><Button Command="{Binding ShowViewACommand}" Content="ViewA" /><Button Command="{Binding ShowViewBCommand}" Content="ViewB" /></UniformGrid></UniformGrid><UniformGrid Grid.Row="1" Rows="1"><ContentControl prism:RegionManager.RegionName="ViewA" /><ContentControl prism:RegionManager.RegionName="ViewB" /></UniformGrid></Grid>
</Window>
public class MainWindowViewModel : BindableBase{[Dependency]public IRegionManager regionManager { get; set; }public MainWindowViewModel(IRegionManager regionManager, IUnionCommand UnionCommand){this.regionManager = regionManager;this.UnionCommand = UnionCommand;}[Dependency]public IUnionCommand UnionCommand { get; set; }public ICommand ShowViewACommand{get => new DelegateCommand(() =>{regionManager.RequestNavigate("ViewA", "ViewA");});}public ICommand ShowViewBCommand{get => new DelegateCommand(() =>{regionManager.RequestNavigate("ViewB", "ViewB");});}}
<UserControl x:Class="WpfApp1.Views.ViewA"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:local="clr-namespace:WpfApp1.Views"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"d:DesignHeight="450"d:DesignWidth="800"mc:Ignorable="d"><Grid><StackPanel VerticalAlignment="Center"><TextBox Text="{Binding ValueA}" /><Button Command="{Binding ValueACommand}" Content="ShouViewA" /></StackPanel></Grid>
</UserControl>
<UserControl x:Class="WpfApp1.Views.ViewB"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:local="clr-namespace:WpfApp1.Views"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"d:DesignHeight="450"d:DesignWidth="800"mc:Ignorable="d"><Grid><StackPanel VerticalAlignment="Center"><TextBox Text="{Binding ValueB}" /><Button Command="{Binding ValueBCommand}" Content="ShouViewB" /></StackPanel></Grid>
</UserControl>
 public class ViewAViewModel : BindableBase{private int _valueA = 0;public int ValueA{get { return _valueA; }set { SetProperty(ref _valueA, value); }}public ICommand ValueACommand { get; set; }public ViewAViewModel(IUnionCommand unionCommand){ValueACommand = new DelegateCommand(() =>{ValueA = 100;});//注册命令
            unionCommand.Commands.RegisterCommand(ValueACommand);}}
 public class ViewBViewModel : BindableBase{private int _valueB = 0;public int ValueB{get { return _valueB; }set { SetProperty(ref _valueB, value); }}public ICommand ValueBCommand { get; set; }public ViewBViewModel(IUnionCommand unionCommand){ValueBCommand = new DelegateCommand(() =>{ValueB = 200;});//注册命令
            unionCommand.Commands.RegisterCommand(ValueBCommand);}}
 public class Startup : PrismBootstrapper{protected override DependencyObject CreateShell(){return Container.Resolve<MainWindow>();//return Container.Resolve<NavigationLogWindow>();//return Container.Resolve<MainWindow>();
        }protected override void RegisterTypes(IContainerRegistry containerRegistry){containerRegistry.RegisterForNavigation<ViewA>();containerRegistry.RegisterForNavigation<ViewB>();containerRegistry.RegisterSingleton<IUnionCommand, UnionCommand>();//containerRegistry.RegisterForNavigation<ViewD>();//containerRegistry.RegisterForNavigation<ViewE>();
        }protected override void ConfigureViewModelLocator(){base.ConfigureViewModelLocator();ViewModelLocationProvider.Register(typeof(MainWindow).ToString(), typeof(MainWindowViewModel));ViewModelLocationProvider.Register(typeof(NavigationWindow).ToString(), typeof(NavigationWindowVewModel));ViewModelLocationProvider.Register(typeof(NavigationLogWindow).ToString(), typeof(NavigationLogViewModel));}}
来源:https://blog.csdn.net/jjailsa/article/details/135732650

 

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

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

相关文章

南沙C++信奥赛老师解一本通题1217:棋盘问题

​【题目描述】在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放 kk 个棋子的所有可行的摆放方案 CC。【输入】输入含有多组测试数据。 每组数据…

文件传输 --- 使用 FTP 在两个主机之前传输文件

FTP 客户端 服务端tcpsvd -vE 0.0.0.0 21 ftpd /app/updater/ -w &共享 /app/updater 的文件给客户端

高可用集群 KEEPALIVED ubuntu使用

1 Keepalived 架构和安装 2.1 Keepalived 架构 Keepalived进程树Keepalived <-- Parent process monitoring children \_ Keepalived <-- VRRP child \_ Keepalived <-- Healthchecking child2.2 Keepalived 环境准备 #环境准备 #两台keepalive机器分别配一个单独网卡…

PHP支付,TP5.0接入支付宝支付流程

一、支付宝沙箱 1.登录支付宝开放平台https://open.alipay.com/;点击右上角的“控制台”菜单 2.下拉到页末找到“沙盒” 配置一下基础信息:配置一下信息,特别注意,网关地址:沙箱环境是有dev的,正式上要去掉 dev; 二、DEMO 1.下载电脑网站支付Demo php版本 2.下载后把整…

无法访问你试图使用的功能所在的网络位置

无法访问你试图使用的功能所在的网络位置、无法删除 xxxx工具的旧版本问题如标题,被这个问题搞吐了。报错如下如:     起因是公司的产品有些周边工具,在分析和排查问题的过程中,遇到上图这个问题,因为要反复卸载和重装,还涉及到不同版本,最后玩坏了。卸载以后,Wind…

EKP qhky 附件A4纸张打印效果

一.需求背景 需求:EKP V16,对于附件打印 开发者一般情况下使用的是 请求直接预览打印 ,但是对于 需要自定义打印文件的大小 需要特别定制!方案:使用 PDF.js 在 JSP 页面中显示 PDF 文件(EKPV16 项目中已引入 PDF.js 库) 定制前效果:定制后效果: 二.Code 其中附件链接 …

Orange Pi + SPI点亮 ws2812

开发板型号:OrangePi One 系统版本:Ubuntu 20.04 focal Desktop 接口:SPI1. 连线 TB上买的ws2812大概长这样:细节标在图上了。 带插头的一端连上即可。其带针脚一端是多组灯带串联时候用。DI接SPI的MOSI。 参考博客[1] 2. 启用硬件SPI 在设置里有一个orangepi-config的执行…

时间格式化标签说明

时间格式化标签和PHP时间格式化语法一致,可以使用不同的字母代替,中间可以穿插任意字符。常见的格式包括:Y:四位数的年份 m:两位数的月份 d:两位数的日期 H:两位数的小时 i:两位数的分钟 s:两位数的秒示例格式 以下是一些示例格式:Y-m-d:2023-09-15 Y/m/d:2023/09/…