Stylet框架

news2024/11/17 12:58:05

Stylet框架

编辑时间:2023/8/25

1.Stylet简介

Stylet是一个小巧但功能强大的MVVM框架,灵感来自Caliburn.Micro。其目的是进一步降低复杂性和魔力(译者注:Caliburn.Micro有很多让人抓狂的约定,看起来像魔法,这对新手而言一点都不友好),让不熟悉任何MVVM框架的人(同事)更快地跟上速度。

它还提供了Caliburn.Micro中不可用的功能,包括自己的IoC容器,简单的ViewModel验证,甚至是与MVVM兼容的MessageBox。

低LOC数量和非常全面的测试套件使其成为使用和验证/验证SOUP具有高开销的项目的一个有吸引力的选择,其模块化工具包架构意味着它很容易使用你喜欢的部分,或者替换你不喜欢的部分。

2.Prism与Stylet对比

Prism 优势:

  1. 模块化架构: Prism 鼓励使用模块化架构,可以将应用程序拆分为独立的模块,每个模块有自己的视图、视图模型和服务。这有助于分离关注点,提高应用程序的可维护性。
  2. 事件聚合器: Prism 提供了事件聚合器,允许模块之间进行松耦合的通信。模块可以发布和订阅事件,从而实现解耦的通信方式。
  3. 导航支持: Prism 提供了强大的导航支持,可以管理复杂的导航流程和导航参数。
  4. 依赖注入: Prism 集成了依赖注入容器,可以帮助管理应用程序中的依赖关系,使代码更加可测试和可扩展。
  5. 文档和社区支持: Prism 有较多的文档和社区支持,有大量的教程、示例和解答。

Prism 劣势:

  1. 学习曲线: 由于 Prism 提供了丰富的功能,初学者可能需要一些时间来掌握其概念和用法。
  2. 较大的库: 由于 Prism 提供了许多功能,它的库大小相对较大,这可能会在一些资源受限的项目中造成一些影响。

Stylet 优势:

  1. 轻量级: Stylet 是一个相对轻量级的框架,专注于提供基本的 MVVM 支持,适用于小到中型的应用程序。
  2. 简单直观: Stylet 的设计使其非常简单直观,对于那些不需要复杂功能的项目来说,它可以更容易上手。
  3. 性能: 由于 Stylet 较为精简,可能在某些情况下具有更好的性能表现。

Stylet 劣势:

  1. 功能有限: Stylet 的功能相对较少,特别是在涉及复杂的模块化、导航和事件通信时可能会有限制。
  2. 缺乏广泛的社区支持: 相比于 Prism,Stylet 的社区规模可能较小,因此找到解决方案和资源可能会更具挑战性。

3.创建stylet程序

3.1创建一个WPF程序,添加stylet引用

在这里插入图片描述

3.2创建一个Bootstrapper.cs的类并编辑

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>
    {

    }
}

3.3更改App.xaml文件

<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>

3.4创建Views文件与ViewModels进行自动绑定使用

在这里插入图片描述

3.5编写xaml代码与C#代码

<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
    }
}

4.增强用法

4.1IOC注入

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();
}

4.2命令绑定

<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" />

4.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); // 发布事件
    }
}

4.4IScreen和Screen

IScreen是一个接口,用于标识一个类作为视图模型。

  • IScreenState:用于激活、停用和关闭 ViewModel。具有Activate 、Deactivate 和 Close方法,以及用于跟踪屏幕状态更改的事件和属性。
  • IGuardClose:用于询问 ViewModel 是否可以关闭。有一个方法CanCloseAsync。
  • IViewAware:有时 ViewModel 需要了解其视图(何时附加、它是什么等)。此接口通过属性View和方法AttachView允许这样做。
  • IHaveDisplayName:有一个DisplayName属性。这个名称被用作使用窗口管理器显示的窗口和对话框的标题,对于像TabControls这样的东西也很有用。
  • IChild:对于 ViewModel 来说,知道 Conductor 在管理它的是什么(例如,请求关闭它)可能是有利的。如果 ViewModel 实现了IChild ,它将被告知这一点。

Screen有一些虚拟方法,如果你愿意,我们鼓励你覆盖:

  • OnInitialActivate:第一次激活屏幕时调用,并且永远不会再调用。对于设置您不想在构造函数中设置的内容非常有用。
  • OnActivate:在屏幕激活时调用。仅当屏幕尚未激活时才会被调用。
  • OnDeactivate:在屏幕停用时调用。仅当屏幕尚未停用时才会被调用。
  • OnClose:在屏幕关闭时调用。只会被调用一次。仅在屏幕停用时调用。
  • OnViewLoaded:在触发 View 的Loaded事件时调用。
  • CanCloseAsync:当Conductor想知道Screen是否可以关闭时调用,默认情况下,返回Task.FromResult(this.CanClose).但您可以在此处添加自己的异步逻辑。
  • CanClose:默认情况下调用CanCloseAsync。如果要决定是否可以同步关闭,请覆盖CanClose 。如果要异步决定,请覆盖 CanCloseAsync。
  • RequestClose(bool? dialogResult = null):当您想向自己的Conductor请求关闭时,您可以调用此方法。如果需要在对话框中显示,则使用 DialogResult 参数。

Screen 派生自PropertyChangedBase,因此很容易引发 PropertyChanged 通知。

4.5Conductor

  1. Conductor
    • Conductor 是最基本的 Conductors 类型,它实现了 IScreen 接口,并提供了管理子视图模型的基本方法。
    • 您可以使用 ActivateItem 方法来激活一个子视图模型。通过激活子视图模型,它将被显示在 UI 中,并且 OnActivate 方法将会被调用。
    • 使用 DeactivateItem 方法可以停用子视图模型,并将其从 UI 中移除。OnDeactivate 方法将会被调用。
  2. Conductor.OneActive
    • Conductor.OneActiveConductor 的一种特殊类型。它专门用于管理多个子视图模型,但只允许一个活动的子视图模型显示。
    • 当激活一个新的子视图模型时,之前的子视图模型将被停用并从 UI 中移除。
  3. Conductor.Collection.OneActive
    • Conductor.Collection.OneActive 是用于管理一组子视图模型的 Conductors 类型。
    • 它允许您在一个 UI 容器中显示多个子视图模型,但只允许一个子视图模型是活动的。
    • 您可以使用 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>

4.6BindableCollection

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);
    }
}

4.7ValidationException

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}");
        }
    }
}

4.8StyletIoC

StyletIoC 是 “Stylet” 框架中的一个轻量级的依赖注入容器。它允许您管理应用程序中的依赖关系,并在需要时自动解析和注入这些依赖关系。使用 StyletIoC,您可以实现松散耦合、可测试和可维护的应用程序架构。

  1. 注册服务:
    • 您可以使用 StyletIoCBuilder 对象来注册服务和它们的实现。
    • 通常,在应用程序的启动代码中,您会初始化 StyletIoC 容器,并使用 .Bind<T>().To<TImplementation>() 或其他方法来注册您的服务。
  2. 解析依赖:
    • 当您需要使用某个服务时,您可以通过 StyletIoC 来解析它。只需从容器中请求所需的服务类型即可。
  3. 生命周期管理:
    • StyletIoC 支持不同的生命周期管理选项,如瞬态(Transient)、单例(Singleton)等。
    • 您可以使用 .InSingletonScope().InTransientScope() 方法来设置服务的生命周期。
  4. 构造函数注入:
    • 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();
    }
}

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

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

相关文章

项目进度管理(4-2)关键链法和关键路径法的区别和联系

1 关键链法和关键路径法的主要区别 1.1 关键链法和关键路径法的关注焦点不同 关键路径法&#xff08;CPM&#xff09;&#xff1a;关注项目中最长的路径&#xff0c;也就是所需时间最长的路径&#xff0c;这被称为关键路径。关键路径决定了项目的最早完成时间。关键链法&…

Jetbrains IDE新UI设置前进/后退导航键

背景 2023年6月&#xff0c;Jetbrains在新发布的IDE&#xff08;Idea、PyCharm等&#xff09;中开放了新UI选项&#xff0c;我们勾选后重启IDE&#xff0c;便可以使用这一魔性的UI界面了。 但是前进/后退这对常用的导航键却找不到了&#xff0c;以前的设置方式&#xff08;Vi…

【2022年电赛】有人开摆,有人跑路,有人5秒不识数

前言&#xff1a;该作品是2022年四川省电子设计竞赛一等奖作品&#xff0c;其能稳定完成全部四个问题&#xff0c;但存在停车距离的精度问题。该文章将会介绍该作品的整体设计思路&#xff0c;关键控制算法等技术相关问题&#xff0c;也会给出工程的下载链接。同时本人参加过20…

考研408 | 【操作系统】 内存管理

内存的基础 内存和内存的作用&#xff1a; 几个常用的数量单位&#xff1a; 指令的工作原理&#xff1a; 问题&#xff1a;如何将指令中的逻辑地址转换为物理地址&#xff1f; 解决办法&#xff1a;装入的三种方式 1.绝对装入 2.可重定位装入 3.动态重定位 从写程序到程…

分布式事务篇-2.2 Seata存储模式,配置模式,注册模式

文章目录 前言一、存储模式:1.1 存储模式的作用&#xff1a;1.2 File 存储模式&#xff1a;1.2.1 映射数据存储文件&#xff1a;1.2.3 file存储优缺点&#xff1a; 1.3 db 存储模式&#xff1a;1.3.1 application.yml 配置db 信息&#xff1a;1.3.1 拷贝驱动jar&#xff1a;1.3…

实验室信息化建设都包括哪些方面?

在现代的计算机通信系统、信息安全系统和自动控制等系统中&#xff0c;软件开发工作占了相当大的比重&#xff0c;而与这些系统有关的软件一般十分庞大&#xff0c;也相当复杂。这些软件还要大量地与操作系统核作深层次的交互&#xff0c;以进行信息的传输、控制和实现各种通信…

#systemverilog# 之 event region 和 timeslot 仿真调度(六)疑惑寄存器采样吗

一 象征性啰嗦 想必大家在刚开始尝试写Verilig HDL代码的时候,都是参考一些列参考代码,有些来自于参考书,有些来自于网上大牛的笔记,甚至有写来自于某宝FPGA开发板的授权代码。我还记得自己当时第一次写代码,参考的是一款Altera 芯片,结合Quartus 开发软件, 在上面练习…

线程池也就那么一回事嘛!

线程池详讲 一、线程池的概述二、线程池三、自定义线程池四、线程池工作流程图五、线程池应用场景 一、线程池的概述 线程池其实就是一种多线程处理形式&#xff0c;处理过程中可以将任务添加到队列中&#xff0c;然后在创建线程后自动启动这些任务。这里的线程就是我们前面学过…

算法笔记:KD树

1 引入原因 K近邻算法需要在整个数据集中搜索和测试数据x最近的k个点&#xff0c;如果一一计算&#xff0c;然后再排序&#xff0c;开销过大 引入KD树的作用就是对KNN搜索和排序的耗时进行改进 2 KD树 2.1 主体思路 以空间换时间&#xff0c;利用训练样本集中的样本点&…

OSPF配置与协议分析

一、实验目的&#xff1a; 通过该实验学习OSPFv2协议&#xff0c;能够通过GNS3模拟环境并用wireshark抓包分析OSPFv2协议的报文格式 二、预备知识&#xff1a; OSPF(Open Shortest Path First&#xff0c;开放式最短路径优先&#xff09;是一个链路状态路由协议&#xff0c;被各…

智能引领物流,AGV与工控机完美搭配!

AGV小车现已广泛被制造业使用&#xff0c;成为智能工厂、智能车间的重要组成部分。在制造业的生产中用AGV小车代替工进行装载、搬运、卸载等工作&#xff0c;实现了车间物流的自动化&#xff0c;极大的提高了生产自动化水平。通过AGV小车与产线进行完美结合&#xff0c;可自动化…

如何理解原假设和备择假设?

原假设H0&#xff1a;一般是想要推翻的结论&#xff0c;如指标没有变化&#xff0c;实验组和对照组的该结果指标没有差异等。 备择假设H1&#xff1a;一般是想要证明的结论&#xff0c;如实验组的指标是显著提升的&#xff0c;指标提升10%等。 反证法的思想&#xff1a;因为假…

到目前为止,所有的关于安卓14的详细介绍

安卓14现在可能已经不远了,谷歌已经进行了五次测试,通常10月份的发布窗口时间很快就会到来。但除了在谷歌I/O 2023上进行简短讨论外,谷歌对正在发生的变化相对沉默。 可以肯定地说,Android 14不会是操作系统有史以来最大的一系列变化,但有很多改进和变化可以让Android保持…

Python Requests模块session的使用建议

本篇主要讲解Python Requests模块session的使用建议及整个会话中的所有cookie的方法。 测试代码 服务端&#xff1a;下面是用flask做的一个服务端&#xff0c;用来设置cookie以及打印请求时的请求头。 # -*- coding: utf-8 -*- from flask import Flask, make_response, req…

容器的基本操作

docker中的容器就是一个轻量级的虚拟机&#xff0c;是镜像运行起来的一个状态&#xff0c;本文就先来看看容器的基本操作。 查看容器 查看容器 启动docker后&#xff0c;使用docker ps命令可以查看当前正在运行的容器&#xff1a; 查看所有容器 上面这条命令是查看当前正在…

Hadoop Hdfs基本命令

0目录 1.hadoop安装问题处理 2.hdfs基本命令 3.上传/下载文件和文件夹 1.hadoop安装问题处理 如果安装有进程无法启动&#xff0c;如下图 重新检查6个配置文件 Core-site.xml \ hdfs-site.xml \ hadoop-env.sh \ yarn-site.xml \ workers \ yarn-site.xml 来到hadoop313目录…

8/26 回溯法 周总结 记录个人的想法

DAY1 77. 组合 这道题是经典的回溯题&#xff0c; 递归函数参数和返回值显而易见 终止条件是path.size()k 递归逻辑&#xff0c;需要理解每次调用回溯的startIndex的含义&#xff0c;图解&#xff1a; DAY2 216. 组合总和 III:这道题与77题作类比&#xff1a; 77&#xff1…

剪绳子c、c++实现

给你一根长度为 n 的绳子&#xff0c;请把绳子剪成整数长的 m 段&#xff08; m 、 n 都是整数&#xff0c; n > 1 并且 m > 1 &#xff0c; m < n &#xff09;&#xff0c;每段绳子的长度记为 k[1],...,k[m] 。请问 k[1]*k[2]*...*k[m] 可能的最大乘积是多少&#x…

【MySQL系列】表的内连接和外连接学习

「前言」文章内容大致是对MySQL表的内连接和外连接。 「归属专栏」MySQL 「主页链接」个人主页 「笔者」枫叶先生(fy) 目录 一、内连接二、外连接2.1 左外连接2.2 右外连接 一、内连接 内连接实际上就是利用where子句对两种表形成的笛卡儿积进行筛选&#xff0c;前面篇章学习的…

ctfshow-web-红包题第六弹

0x00 前言 CTF 加解密合集CTF Web合集 0x01 题目 0x02 Write Up 首先跑一下字典&#xff0c;这里用的dirmap,可以看到有一个web.zip 下载下来之后发现是一个网站备份&#xff0c;备份的是check.php.bak 然后接着看&#xff0c;可以看到这里不太可能是sql注入&#xff0c;有…