Stylet:基础入门





5.00/5 (4投票s)
Stylet MVVM 框架概述。
引言
Stylet 是一个小型 MVVM 框架,支持模块化 WPF 应用程序的开发。它旨在通过减少实现某些 MVVM 功能所需的代码量来简化创建 WPF-MVVM 应用程序的过程。在本文中,我将简要介绍其中一些功能,但请注意,本文不是 WPF 或 MVVM 的介绍。如果您想轻松跟上,应该了解这两者。
背景
我之前写过关于 Prism 和 MvvmCross 的文章,使用的是一个显示代表虚构员工的卡片的示例应用程序。本文遵循相同的模式:示例应用程序中有带有部分员工详细信息的卡片,点击卡片会导航到显示特定员工更多详细信息的页面。

示例应用程序包含三个项目:一个 .NET Core WPF 应用程序项目和两个 .NET Core 类库项目;一个包含共享代码,另一个包含 Stylet 模块。

您可以从 GitHub 克隆或下载示例项目。
Stylet
根视图模型与导体
要在 WPF 应用程序项目中使用 Stylet,您必须引用 Stylet NuGet 包。然后,您必须创建根视图和根视图模型,它们将根据命名约定关联起来。根视图必须是 Window
,它充当您应用程序的外壳。在示例项目中,ShellViewModel
是根视图模型。
using Stylet;
namespace StaffStuff.ViewModels
{
public class ShellViewModel : Conductor<IScreen>.StackNavigation
{
public ShellViewModel(StaffViewModel staffViewModel)
{
this.DisplayName = string.Empty;
this.ActivateItem(staffViewModel);
}
}
}
ShellViewModel
继承自 Stylet 的 Conductor<T>.StackNavigation
。导体负责管理其拥有的视图模型或视图模型的生命周期。它决定视图模型是激活、停用还是关闭。Conductor<T>.StackNavigation
是一个提供基于堆栈导航的导体。在示例应用程序中,导体将支持从卡片视图导航到详细信息视图。
在 ShellViewModel
的构造函数中,一个视图模型作为依赖项传入并设置为活动项。由于 ShellViewModel
是一个导体,它现在拥有 StaffViewModel
并将管理其生命周期。在 ShellView
中,活动项(或者说与活动项关联的视图)将放置在 ContentControl
中。
<Window x:Class="StaffStuff.Views.ShellView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="https://github.com/canton7/Stylet"
Background="#FF0D2738"
Height="480" Width="800"
WindowStartupLocation="CenterScreen">
<Grid>
<ContentControl s:View.Model="{Binding ActiveItem}"/>
</Grid>
</Window>
ActiveItem
是导体的一个属性,通过调用导体的 ActivateItem()
方法来设置。
Bootstrapper
在放置好根视图模型后,Stylet 要求您创建一个引导程序,您可以在其中指定根视图模型。
namespace StaffStuff
{
public class Bootstrapper : Bootstrapper<ShellViewModel>
{
protected override void ConfigureIoC(IStyletIoCBuilder builder)
{
builder.AddModule(new ServicesModule());
}
}
}
然后,您将 Stylet 的 ApplicationLoader
添加为应用程序资源,并设置引导程序以加载。
<Application x:Class="StaffStuff.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:StaffStuff"
xmlns:s="https://github.com/canton7/Stylet">
<Application.Resources>
<s:ApplicationLoader>
<s:ApplicationLoader.Bootstrapper>
<local:Bootstrapper/>
</s:ApplicationLoader.Bootstrapper>
</s:ApplicationLoader>
</Application.Resources>
</Application>
除了设置根视图模型外,引导程序也是您可以将类型注册到 Stylet 的 IoC 容器的地方。这在 ConfigureIoC()
中使用 StyleIoCBuilder
完成,因此您可以执行诸如 builder.Bind<IStaffData>().To<StaffData>()
之类的操作。在示例项目的引导程序中,我向构建器添加了一个模块:builder.AddModule(new ServicesModule())
。
模块
如引言中所述,Stylet 支持模块化 WPF-MVVM 应用程序的开发。要创建 Stylet 模块,您需要创建一个 .NET Core 类库项目,该项目引用 Stylet NuGet 包,并在项目根目录添加一个派生自 StyletIoCModule
的类。然后,可以在模块的 Load()
方法中将类型注册到 IoC 容器。
using StaffStuff.Common.Interfaces;
using StaffStuff.Services.Services;
using StyletIoC;
namespace StaffStuff.Services
{
public class ServicesModule : StyletIoCModule
{
protected override void Load()
{
Bind<IStaffData>().To<StaffData>().InSingletonScope();
}
}
}
屏幕截图
Screen
为派生自它的视图模型提供验证、属性更改通知和活动状态监视。它还包含一个 Parent
属性,该属性使视图模型能够知道哪个 Conductor
正在管理它,并允许它请求导体关闭它或激活另一个视图模型。在示例项目中,StaffViewModel
(由 ShellViewModel
激活的第一个视图模型)派生自 Screen
类。
using StaffStuff.Common.Interfaces;
using StaffStuff.Common.Models;
using Stylet;
using System.Collections.Generic;
namespace StaffStuff.ViewModels
{
public class StaffViewModel : Screen
{
private readonly IStaffData _staffData;
public StaffViewModel(IStaffData staffData)
{
_staffData = staffData;
}
private List<Employee> _employees;
public List<Employee> Employees
{
get => _employees;
set => SetAndNotify(ref _employees, value);
}
protected override void OnInitialActivate()
{
Employees = _staffData.GetEmployees();
}
public void StaffDetails(Employee employee)
{
var staffDetailsVM = new StaffDetailsViewModel { Employee = employee };
((ShellViewModel)this.Parent).ActivateItem(staffDetailsVM);
}
}
}
OnInitialActivate()
仅在视图模型首次激活时被调用一次。StaffViewModel
的 StaffDetails()
方法调用导体的 ActivateItem()
方法,请求它激活 StaffDetailsViewModel
,从而触发导航到其关联视图。
using StaffStuff.Common.Models;
using Stylet;
namespace StaffStuff.ViewModels
{
public class StaffDetailsViewModel : Screen
{
public StaffDetailsViewModel() { }
private Employee _employee;
public Employee Employee
{
get => _employee;
set => SetAndNotify(ref _employee, value);
}
public void GoBack()
{
this.RequestClose();
}
}
}
GoBack()
调用 Screen
的 RequestClose()
方法,该方法会触发导体关闭视图模型。这会通过重新激活导体的先前活动项来触发导航回上一个视图——由于导体是 Conductor<T>.StackNavigation
类型,通过调用导体的 GoBack()
方法也可以触发导航回上一个活动项。
public void GoBack()
{
((ShellViewModel)this.Parent).GoBack();
}
Actions
您可能已经注意到,StaffViewModel
和 StaffDetailsViewModel
都没有任何 ICommand
属性。这是因为 Stylet 省去了这些属性,而是允许您视图模型中的一个方法被设置为 Button
的 Command
属性的值。Stylet 通过 Action
来实现这一点。
<Button Command="{s:Action GoBack}">
...
</Button>
<DataTemplate x:Key="StaffDataTemplate" DataType="{x:Type models:Employee}">
<Border Margin="10" Cursor="Hand" BorderThickness="1"
Background="#FF16394F" BorderBrush="#FF3F5666"
CornerRadius="8" Width="200" Height="240">
...
<behaviors:Interaction.Triggers>
<behaviors:EventTrigger EventName="MouseLeftButtonUp">
<behaviors:InvokeCommandAction Command="{s:Action StaffDetails}"
CommandParameter="{Binding}"/>
</behaviors:EventTrigger>
</behaviors:Interaction.Triggers>
</Border>
</DataTemplate>
请注意,如果您的方法需要传递参数,您也可以将 CommandParameter
的值传递给您的方法。
结论
就是这样!这就是运行示例应用程序所需的所有内容。我认为 Stylet 非常棒,文档也非常全面,尽管如果它为应用程序和模块项目设置提供 Visual Studio 模板,那就更好了——目前没有像 Prism 那样的 Visual Studio 扩展来支持这一点,但希望将来会有。如果您有兴趣进一步了解该框架,我鼓励您阅读 文档 并查看 Stylet 仓库中的 示例 项目。
历史
- 2020 年 7 月 21 日:初稿