本章通过自学分享一些Avalonia ReactiveUI MVVM 模式之命令绑定经验,有不对之处,欢迎各位大佬给予纠正。
一、MVVM介绍
关于MVVM介绍,以下来自Avalonia文档

Model-View-View Model(MVVM)模式是一种常见的UI应用程序结构方式。它使用数据绑定系统来帮助在视图和视图模型之间传递数据。这意味着它实现了应用程序逻辑(视图模型)与UI显示(视图)的分离。
应用程序逻辑与业务服务(模型)之间的分离通常通过依赖注入(DI)系统来实现。
对于简单的应用程序来说,MVVM可能有些过度设计;但随着应用程序的发展,往往会出现在同一UI组件模块中保持显示定义和应用程序逻辑的问题:
UI组件之间的交互变得复杂且容易出错。由于依赖于目标UI平台,对UI组件进行单元测试变得困难。
MVVM通过将应用程序逻辑抽象为仅包含代码的类来解决这个问题,这些类不依赖于目标UI平台,因此可以独立进行单元测试。
二、现在开始,我们用VS创建一个Avalonia .NET MVVM App (AvaloniaUl)项目,MVVM Toolkit选择ReactiveUI (关键)

三、基本按钮功能实现
1.修改ViewsMainWindow.axaml文件,在视图中添加一个按钮控件,代码如下:
<Window xmlns=”https://github.com/avaloniaui”
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
xmlns:vm=”using:AvaloniaApplication2.ViewModels”
xmlns:d=”http://schemas.microsoft.com/expression/blend/2008″
xmlns:mc=”http://schemas.openxmlformats.org/markup-compatibility/2006″
mc:Ignorable=”d” d:DesignWidth=”800″ d:DesignHeight=”450″
x:Class=”AvaloniaApplication2.Views.MainWindow”
x:DataType=”vm:MainWindowViewModel”
Icon=”/Assets/avalonia-logo.ico”
Title=”AvaloniaApplication2″><Design.DataContext>
<!– This only sets the DataContext for the previewer in an IDE,
to set the actual DataContext for runtime, set the DataContext property in code (look at App.axaml.cs) –>
<vm:MainWindowViewModel/>
</Design.DataContext>
<StackPanel>
<TextBlock Text=”{Binding Greeting, Mode=TwoWay}” HorizontalAlignment=”Center” VerticalAlignment=”Center”/><!–执行ViewModelsMainWindowViewModel.cs文件中Execute函数–>
<Button Command=”{Binding Execute}”>Execute</Button>
</StackPanel>
</StackPanel>
</Window>
2.修改ViewModelsMainWindowViewModel.cs文件,代码如下:
using ReactiveUI;
namespace AvaloniaApplication2.ViewModels
{
public class MainWindowViewModel : ViewModelBase
{
private string _greeting = “欢迎使用Avalonia!”;
public string Greeting
{
get => _greeting;
set => this.RaiseAndSetIfChanged(ref _greeting, value);
}public void Execute()
{
Greeting = System.DateTime.Now.ToString();
}
}
}
3.以上已经实现了简单命令绑定,程序运行后,每次点击文本框会更新当前时间。

四、ReactiveCommand方法
第三部分绑定能够满足大部分功能需求。但在特定情况下,我们使用ReactiveCommand方式,例如基于任务(异步)、按钮状态(判断是否可用)、观察者模式、组合模式等,下面开始介绍这几种方式的实现。
官方文档参考:https://www.reactiveui.net/docs/handbook/commands/index.html
CreateFromObservable() 观察都模式
CreateFromTask() 通过任务,使用async/await 支持异步
Create() 同步模式
CreateCombined() 执行一个或多个命令
4.1 Create() 同步模式
MainWindow.axaml文件无需改动,第一步修改ViewModelsMainWindowViewModel.cs文件,代码如下:
1.创建Execute函数
public ReactiveCommand<Unit, Unit> Execute { get; }
2.给Execute函数指定动作ExecuteAction
Execute = ReactiveCommand.Create(ExecuteAction);
3.创建ExecuteAction函数
public void ExecuteAction()
{
Greeting = System.DateTime.Now.ToString();
}
ViewModelsMainWindowViewModel.cs
using ReactiveUI;
using System.Reactive;namespace AvaloniaApplication2.ViewModels
{
public class MainWindowViewModel : ViewModelBase
{
private string _greeting = “欢迎使用Avalonia!”;public ReactiveCommand<Unit, Unit> Execute { get; }
public MainWindowViewModel()
{
Execute = ReactiveCommand.Create(ExecuteAction);
}
public string Greeting
{
get => _greeting;
set => this.RaiseAndSetIfChanged(ref _greeting, value);
}public void ExecuteAction()
{
Greeting = System.DateTime.Now.ToString();
}
}
}
我们已经实现ReactiveCommand方法绑定命令,程序运行后,每次点击后,文本框更新当前时间。是不是感觉多了好多行代码,还是和上面功能一样,不过确实是,如果你只是这样ReactiveCommand方法,真还不如不改,因为我们还是同步执行。
4.2 CreateFromTask() 基于任务(同步)
我们对1.1代码做下简单修改,以实现异步执行(关于同步和异步区别这里不介绍)
将ReactiveCommand.Create() 替换为ReactiveCommand.CreateFromTask()
将ExecuteAction函数声明为异步方式: public async Task ExecuteAction(Unit msg)
ViewModelsMainWindowViewModel.cs
using ReactiveUI;
using System.Reactive;
using System.Threading.Tasks;namespace AvaloniaApplication2.ViewModels
{
public class MainWindowViewModel : ViewModelBase
{
private string _greeting = “欢迎使用Avalonia!”;public ReactiveCommand<Unit, Unit> Execute { get; }
public MainWindowViewModel()
{
Execute = ReactiveCommand.CreateFromTask<Unit>(ExecuteAction);
}
public string Greeting
{
get => _greeting;
set => this.RaiseAndSetIfChanged(ref _greeting, value);
}public async Task ExecuteAction(Unit msg)
{await Task.Delay(5000); // 等待5秒
Greeting = System.DateTime.Now.ToString();
}
}
}程序运行后,点击
程序运行后,点击Execute按钮,5秒后文本框更新当前时间。在这5秒内不会影响你鼠标和键盘和键盘操作,窗口也会随意移动,状态不会出现卡死状态,这就是异步程序最大好处,在这个程序里感觉用处不大,但频繁web请求和数据库操作时非常有用。
4.3 CreateFromObservable() 观察都模式
说实话,观察者模式我也不是完全理解。
下面我列举几个观察者模式代码(最基本功能):
定时执行任务
using ReactiveUI;
using System;
using System.Reactive;
using System.Reactive.Linq;
using System.Threading.Tasks;namespace AvaloniaApplication2.ViewModels
{
public class MainWindowViewModel : ViewModelBase
{
private string _greeting = “欢迎使用Avalonia!”;public ReactiveCommand<string, DateTime> Execute { get; }
public MainWindowViewModel()
{
Execute = ReactiveCommand.CreateFromObservable<string, DateTime>(ExecuteAction);
Execute.Subscribe(v => ShowObservableResult(v));
}
public string Greeting
{
get => _greeting;
set => this.RaiseAndSetIfChanged(ref _greeting, value);
}private IObservable<DateTime> ExecuteAction(string arg)
{
return Observable.Interval(TimeSpan.FromSeconds(1)).Select(_ => System.DateTime.Now);}
private void ShowObservableResult(DateTime v)
{
Greeting = v.ToString();
}
}
}
程序运行后,文本框变成了一个时钟,每秒都会更新时间。



