编辑时间:2023/8/25
Stylet是一个小巧但功能强大的MVVM框架,灵感来自Caliburn.Micro。其目的是进一步降低复杂性和魔力(译者注:Caliburn.Micro有很多让人抓狂的约定,看起来像魔法,这对新手而言一点都不友好),让不熟悉任何MVVM框架的人(同事)更快地跟上速度。
它还提供了Caliburn.Micro中不可用的功能,包括自己的IoC容器,简单的ViewModel验证,甚至是与MVVM兼容的MessageBox。
低LOC数量和非常全面的测试套件使其成为使用和验证/验证SOUP具有高开销的项目的一个有吸引力的选择,其模块化工具包架构意味着它很容易使用你喜欢的部分,或者替换你不喜欢的部分。
Prism 优势:
Prism 劣势:
Stylet 优势:
Stylet 劣势:
using Stylet;
using System;
using System.Windows.Threading;
using System.Windows;
using System.Data;
using WPF_Style.ViewModel;
namespace WPF_Style
{
public class Bootstrapper : Bootstrapper<ViewModel.ViewModels.MainViewModel>
{
}
}
<Application x:Class="WPF_Style.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WPF_Style"
xmlns:s="https://github.com/canton7/Stylet">
<Application.Resources>
<s:ApplicationLoader>
<s:ApplicationLoader.Bootstrapper>
<local:Bootstrapper />
s:ApplicationLoader.Bootstrapper>
s:ApplicationLoader>
Application.Resources>
Application>
<Window
x:Class="WPF_Style.Views.MainView"
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:WPF_Style.Views"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:s="https://github.com/canton7/Stylet"
Title="MainView"
Width="800"
Height="450"
mc:Ignorable="d">
<Grid>
<TextBox
Width="165"
Height="39"
Margin="291,110,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Text="{Binding UserName}"
TextWrapping="Wrap" />
<Button
Width="109"
Height="39"
Margin="319,178,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Click="{s:Action btnClick}"
Content="刷新" />
Grid>
Window>
using Stylet;
using System;
namespace WPF_Style.ViewModels
{
public class MainViewModel : Screen
{
public MainViewModel()
{
}
#region 属性
private string _userName = "2222";
public string UserName
{
get { return _userName; }
set { SetAndNotify(ref _userName, value); }
}
#endregion
#region 事件
public void btnClick(object sender, EventArgs e)
{
UserName = "123456";
}
#endregion
}
}
public class Bootstrapper : Bootstrapper<MainViewModel>
{
protected override void OnStart()
{
// This is called just after the application is started, but before the IoC container is set up.
// Set up things like logging, etc
}
protected override void ConfigureIoC(IStyletIoCBuilder builder)
{
// Bind your own types. Concrete types are automatically self-bound.
//builder.Bind<ITestService>().To<TestService>().InSingletonScope();
//builder.AddModule<FeatureSetModule>()
}
protected override void Configure()
{
// This is called after Stylet has created the IoC container, so this.Container exists, but before the
// Root ViewModel is launched.
// Configure your services, etc, in here
}
protected override void OnLaunch()
{
// This is called just after the root ViewModel has been launched
// Something like a version check that displays a dialog might be launched from here
}
protected override void OnExit(ExitEventArgs e)
{
// Called on Application.Exit
}
protected override void OnUnhandledException(DispatcherUnhandledExceptionEventArgs e)
{
// Called on Application.DispatcherUnhandledException
}
}
private readonly ITestService _test;
private readonly IModule _module;
public MainViewModel(ITestService test,IModule module)
{
_test = test;
_module = module;
_module.Initialize();
}
<Button
Width="109"
Height="39"
Command="{s:Action btnClick}"
Content="按钮1" />
<Button
Width="109"
Height="39"
Click="{s:Action btnClick}"
Content="按钮2" />
<Button
Width="109"
Height="39"
s:View.ActionTarget="{Binding MainViewModel}"
Command="{s:Action btnClick}"
Content="按钮3" />
实现订阅-发布模式通常是通过使用内置的事件聚合器(Event Aggregator)来实现的。事件聚合器允许不同的部分(例如视图模型)在没有直接依赖的情况下进行通信,从而实现松耦合。
定义事件:
public class MyEvent
{
public string Message { get; set; }
}
订阅者视图模型:
using Stylet;
public class SubscriberViewModel : Screen, IHandle<MyEvent>
{
private readonly IEventAggregator _eventAggregator;
public string ReceivedMessage { get; set; }
public SubscriberViewModel(IEventAggregator eventAggregator)
{
_eventAggregator = eventAggregator;
_eventAggregator.Subscribe(this); // 订阅事件
}
// 实现 IHandle<MyEvent> 接口的方法,处理事件
public void Handle(MyEvent message)
{
ReceivedMessage = message.Message;
}
}
发布者视图模型:
using Stylet;
public class PublisherViewModel : Screen
{
private readonly IEventAggregator _eventAggregator;
public PublisherViewModel(IEventAggregator eventAggregator)
{
_eventAggregator = eventAggregator;
}
public void PublishEvent()
{
var myEvent = new MyEvent
{
Message = "Hello from the publisher!"
};
_eventAggregator.Publish(myEvent); // 发布事件
}
}
IScreen是一个接口,用于标识一个类作为视图模型。
Screen有一些虚拟方法,如果你愿意,我们鼓励你覆盖:
Screen 派生自PropertyChangedBase,因此很容易引发 PropertyChanged 通知。
Conductor
:
Conductor
是最基本的 Conductors 类型,它实现了 IScreen
接口,并提供了管理子视图模型的基本方法。ActivateItem
方法来激活一个子视图模型。通过激活子视图模型,它将被显示在 UI 中,并且 OnActivate
方法将会被调用。DeactivateItem
方法可以停用子视图模型,并将其从 UI 中移除。OnDeactivate
方法将会被调用。Conductor.OneActive
:
Conductor.OneActive
是 Conductor
的一种特殊类型。它专门用于管理多个子视图模型,但只允许一个活动的子视图模型显示。Conductor.Collection.OneActive
:
Conductor.Collection.OneActive
是用于管理一组子视图模型的 Conductors 类型。Items
属性来管理子视图模型的集合。代码示例:
using Stylet;
public class ParentViewModel : Conductor<IScreen>.Collection.OneActive
{
public void ShowChildViewModel()
{
var childViewModel = new ChildViewModel();
ActivateItem(childViewModel); // 激活子视图模型
}
}
public class ChildViewModel : Screen
{
// 子视图模型的属性和逻辑
}
<Window x:Class="MyNamespace.ConductorViewModel"
xmlns:s="https://github.com/canton7/Stylet" ....>
<ContentControl s:View.Model="{Binding ActiveItem}"/>
Window>
BindableCollection
继承自**System.Collections.ObjectModel.ObservableCollection
**,因此它继承了 ObservableCollection 的功能,如自动通知界面更改。
• 新增方法:AddRange,RemoveRange,Refresh
• 线程安全
代码示例:
using Stylet;
using System.Collections.ObjectModel;
public class MyViewModel : Screen
{
private readonly BindableCollection<string> _items = new BindableCollection<string>();
public BindableCollection<string> Items
{
get { return _items; }
}
public MyViewModel()
{
_items.Add("Item 1");
_items.Add("Item 2");
_items.Add("Item 3");
}
public void AddNewItem()
{
_items.Add("New Item");
}
public void RemoveItem(string item)
{
_items.Remove(item);
}
}
ValidationException
是一个异常类,用于表示数据验证失败时的异常。当使用数据绑定或验证时,如果数据不符合预期的规则或条件,就可以引发 ValidationException
来表示出现了验证错误。
代码示例:
using Stylet;
using System;
public class MyViewModel : Screen
{
private string _name;
public string Name
{
get { return _name; }
set
{
if (string.IsNullOrWhiteSpace(value))
{
throw new ValidationException("Name cannot be empty.");
}
_name = value;
}
}
public void Save()
{
try
{
// 在保存数据之前,进行数据验证
Name = "";
// 保存数据逻辑
Console.WriteLine("Data saved successfully.");
}
catch (ValidationException ex)
{
Console.WriteLine($"Validation error: {ex.Message}");
}
}
}
StyletIoC
是 “Stylet” 框架中的一个轻量级的依赖注入容器。它允许您管理应用程序中的依赖关系,并在需要时自动解析和注入这些依赖关系。使用 StyletIoC
,您可以实现松散耦合、可测试和可维护的应用程序架构。
StyletIoC
的 Builder
对象来注册服务和它们的实现。StyletIoC
容器,并使用 .Bind().To()
或其他方法来注册您的服务。StyletIoC
来解析它。只需从容器中请求所需的服务类型即可。StyletIoC
支持不同的生命周期管理选项,如瞬态(Transient)、单例(Singleton)等。.InSingletonScope()
或 .InTransientScope()
方法来设置服务的生命周期。StyletIoC
支持通过构造函数进行依赖注入。当您创建视图模型或服务实例时,构造函数中声明的依赖将会自动被解析和注入。代码示例:
using Stylet;
public class MyService
{
public string GetMessage()
{
return "Hello from MyService!";
}
}
public class MyViewModel : Screen
{
private readonly MyService _myService;
public MyViewModel(MyService myService)
{
_myService = myService;
}
public string DisplayMessage => _myService.GetMessage();
}
public class Bootstrapper : Bootstrapper<ShellViewModel>
{
protected override void ConfigureIoC(IStyletIoCBuilder builder)
{
builder.Bind<MyService>().ToSelf().InSingletonScope();
}
}