Commanding

除了提供对要在视图中显示或编辑的数据的访问之外,ViewModel还可能定义可由用户执行的一个或多个动作或操作。用户可以通过UI执行的动作或操作通常被定义为命令。命令提供了一种方便的方法来表示可以轻松绑定到UI中的控件的操作或操作。它们封装了实现操作或操作的实际代码,并有助于使其与视图中的实际可视化表示分离。

当用户与视图交互时,用户可以以多种不同的方式直观地表示和调用命令。在大多数情况下,它们是通过鼠标单击调用的,但也可以通过快捷键按下,触摸手势或任何其他输入事件来调用它们。视图中的控件是绑定到ViewModel命令的数据,以便用户可以使用控件定义的任何输入事件或手势来调用它们。视图中的UI控件与命令之间的交互可以是双向的。在这种情况下,可以在用户与UI交互时调用该命令,并且可以在启用或禁用基础命令时自动启用或禁用UI。

ViewModel可以将命令实现为命令对象(实现ICommand接口的对象)。可以以声明方式定义视图与命令的交互,而无需在视图的代码隐藏文件中使用复杂的事件处理代码。例如,某些控件固有地支持命令并提供Command可以是绑定到ICommandViewModel提供的对象的数据的属性。在其他情况下,命令行为可用于将控件与ViewModel提供的命令方法或命令对象相关联。

实现ICommand界面很简单。Prism提供了DelegateCommand这个界面的实现,您可以在应用程序中轻松使用它。

[Using Delegate Commands视频教程](Prism.assets/Prism - Using Delegate Commands.mp4)

DelegateCommand

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

public class ArticleViewModel
{
public DelegateCommand SubmitCommand { get; private set; } public ArticleViewModel()
{
SubmitCommand = new DelegateCommand<object>(Submit, CanSubmit);
} void Submit(object parameter)
{
//implement logic
} bool CanSubmit(object parameter)
{
return true;
}
}

DelegateCommand对象上调用Execute方法时,它只是通过您在构造函数中指定的委托将调用转发到ViewModel类中的方法。同样,CanExecute调用该方法时,将调用ViewModel类中的相应方法。CanExecute构造函数中方法的委托是可选的。如果没有指定一个委托,DelegateCommand将始终返回trueCanExecute

DelegateCommand班是一个泛型类型。type参数指定传递给ExecuteCanExecute方法的命令参数的类型。在前面的示例中,command参数是type object非通用的版本DelegateCommand类也通过棱镜用于提供当没有所需的命令参数,并且被定义为如下:

public class ArticleViewModel
{
public DelegateCommand SubmitCommand { get; private set; } public ArticleViewModel()
{
SubmitCommand = new DelegateCommand(Submit, CanSubmit);
} void Submit()
{
//implement logic
} bool CanSubmit()
{
return true;
}
}

所述DelegateCommand故意阻止使用值类型(int,双,布尔等)。因为ICommand需要一个object具有值类型T将导致当意外行为CanExecute(null)XAML初始化命令绑定期间被调用。使用default(T)被认为是被拒绝作为解决方案,因为实现者无法区分有效值和默认值。如果要将值类型用作参数,则必须使用DelegateCommand<Nullable<int>>或使用简写?语法(DelegateCommand<int?>)使其可为空。

从View调用DelegateCommands

有许多方法可以将视图中的控件与ViewModel提供的命令对象相关联。某些WPF,Xamarin.Forms和UWP控件可以通过Command属性轻松地绑定到命令对象。

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

也可以使用CommandParameter属性选择性地定义命令参数。期望参数的类型在DelegateCommand<T>泛型声明中指定。当用户与该控件交互时,控件将自动调用目标命令,并且命令参数(如果提供)将作为参数传递给命令的Execute方法。在前面的示例中,按钮将SubmitCommand在单击时自动调用。此外,如果CanExecute指定了委托,则CanExecute返回时将自动禁用该按钮,如果返回false则将启用该按钮true

Raising Change Notifications

ViewModel通常需要指示命令CanExecute状态的更改,以便UI中绑定到该命令的任何控件都将更新其启用状态以反映绑定命令的可用性。在DelegateCommand提供了几种这些通知发送到用户界面。

RaiseCanExecuteChanged

RaiseCanExecuteChanged每当需要手动更新绑定的UI元素的状态时,请使用该方法。例如,当IsEnabled属性值更改时,我们调用RaiseCanExecuteChanged属性的setter来通知UI状态更改。

private bool _isEnabled;
public bool IsEnabled
{
get { return _isEnabled; }
set
{
SetProperty(ref _isEnabled, value);
SubmitCommand.RaiseCanExecuteChanged();
}
}

ObservesProperty

如果命令应在属性值更改时发送通知,则可以使用该ObservesProperty方法。使用该ObservesProperty方法时,只要提供的属性的值发生更改,DelegateCommand将自动调用RaiseCanExecuteChanged以通知UI状态更改。

public class ArticleViewModel : BindableBase
{
private bool _isEnabled;
public bool IsEnabled
{
get { return _isEnabled; }
set { SetProperty(ref _isEnabled, value); }
} public DelegateCommand SubmitCommand { get; private set; } public ArticleViewModel()
{
SubmitCommand = new DelegateCommand(Submit, CanSubmit).ObservesProperty(() => IsEnabled);
} void Submit()
{
//implement logic
} bool CanSubmit()
{
return IsEnabled;
}
}

注意

使用该ObservesProperty方法时,您可以链接注册多个属性以供观察。示例:ObservesProperty(() => IsEnabled).ObservesProperty(() => CanSave)

ObservesCanExecute

如果您CanExecute是简单Boolean属性的结果,则可以省去声明CanExecute委托,并使用该ObservesCanExecute方法。ObservesCanExecute当注册的属性值发生变化时,它不仅会向UI发送通知,而且还会使用与实际CanExecute委托相同的属性。

public class ArticleViewModel : BindableBase
{
private bool _isEnabled;
public bool IsEnabled
{
get { return _isEnabled; }
set { SetProperty(ref _isEnabled, value); }
} public DelegateCommand SubmitCommand { get; private set; } public ArticleViewModel()
{
SubmitCommand = new DelegateCommand(Submit, CanSubmit).ObservesCanExecute(() => IsEnabled);
} void Submit()
{
//implement logic
}
}
警告

不要尝试链式注册ObservesCanExecute方法。CanExcute代表只能观察到一个属性。

基于Task-Based的DelegateCommand

async/await调用Execute委托内部的异步方法是一个非常常见的要求。每个人的第一直觉是他们需要一个AsyncCommand,但这种假设是错误的。ICommand本质上是同步的,并且代表ExecuteCanExecute代表应被视为事件。这意味着这async void是一个非常有效的语法用于命令。使用异步方法有两种方法DelegateCommand

  • 方法一
public class ArticleViewModel
{
public DelegateCommand SubmitCommand { get; private set; } public ArticleViewModel()
{
SubmitCommand = new DelegateCommand(Submit);
} async void Submit()
{
await SomeAsyncMethod();
}
}
  • 方法二
public class ArticleViewModel
{
public DelegateCommand SubmitCommand { get; private set; } public ArticleViewModel()
{
SubmitCommand = new DelegateCommand(async ()=> await Submit());
} Task Submit()
{
return SomeAsyncMethod();
}
}

Prism_Commanding(2)的更多相关文章

随机推荐

  1. netcore在CentOS7 下使用处理图片的问题

    请看代码,当你在centos下要把图片转为Base64的时候 MemoryStream ms = new MemoryStream(); try { Bitmap bmp = new Bitmap(f ...

  2. Linux_crontab参数表示的意思

    *       *      *       *      * (下面的字体对应) 分     时    日    月    周 星号(*):代表所有可能的值,例如month字段如果是星号,则表示在满 ...

  3. asp.net core 3.0获取web应用的根目录

    目录 1.需求 2.解决方案 1.需求 asp.net core 3.0的web项目中,在controller中,想要获取wwwroot下的imgs/banners文件夹下的所有文件: 在传统的asp ...

  4. Vue之判断对象是否为空的方法

    1. JSON.stringify(xxx)=='{}' 2. Object.keys(xxx).length==0 验证结果如下:

  5. AST抽象语法树 Javascript版

    在javascript世界中,你可以认为抽象语法树(AST)是最底层. 再往下,就是关于转换和编译的"黑魔法"领域了. 现在,我们拆解一个简单的add函数 function add ...

  6. C++做四则运算的MFC计算器(二)栈转换和计算后缀表达式

    上篇写了MFC界面搭建,这篇就写实现计算.涉及到数据结构,对新手很不友好. 虽然是MFC程序,但是能灵活地分离后台代码,自行构建控制台程序. 上篇文章链接:C++做四则运算的MFC计算器(一)MFC界 ...

  7. LeetCode H2O 生成

    第1117题 现在有两种线程,氢 oxygen 和氧 hydrogen,你的目标是组织这两种线程来产生水分子. 存在一个屏障(barrier)使得每个线程必须等候直到一个完整水分子能够被产生出来. 氢 ...

  8. 小程序实现日期时间控件picker

    小程序自带的组件中有日期跟时间的picker,但就缺个日期时间picker组件,那没办法,只能自己弄一个,这个组件不是很难,比较难的地方是要根据不同年份(是否闰年)跟月份决定一个月里有多少天. 我直接 ...

  9. HeadFirst设计模式<2>

    HeadFirst设计模式<2> 1 装饰者模式 星巴克咖啡 饮料 总结 如果说策略模式是通过组合实现弹性,那么装饰者模式就是通过继承来实现,在实现的同时,客户基本感觉不到使用了装饰者模式 ...

  10. Springboot vue.js html 跨域 前后分离 Activiti6 工作流 集成代码生成器 shiro 权限

    官网:www.fhadmin.org 特别注意: Springboot 工作流  前后分离 + 跨域 版本 (权限控制到菜单和按钮) 后台框架:springboot2.1.2+ activiti6.0 ...