【愚公系列】2023年03月 .NET CORE工具案例-Caliburn.Micro的使用基于WPF的改造的MVVM案例

举报
愚公搬代码 发表于 2023/03/31 22:26:16 2023/03/31
【摘要】 前言 1.Caliburn.Micro是什么Caliburn.Micro是一个微软开发的用于构建WPF,Silverlight和Windows Phone应用程序的MVVM(模型-视图-视图模型)框架。它提供了一系列的工具和类,帮助开发人员更快,更轻松地构建美观的和可维护的应用程序。 2.Caliburn.Micro的主要功能Caliburn.Micro是一个小型MVVM框架,主要提供了以...

前言

1.Caliburn.Micro是什么

Caliburn.Micro是一个微软开发的用于构建WPF,Silverlight和Windows Phone应用程序的MVVM(模型-视图-视图模型)框架。它提供了一系列的工具和类,帮助开发人员更快,更轻松地构建美观的和可维护的应用程序。

2.Caliburn.Micro的主要功能

Caliburn.Micro是一个小型MVVM框架,主要提供了以下功能:

  1. 简化MVVM模式的实施
  2. 视图绑定
  3. 统一方式的消息机制
  4. 基于事件和命令的行为触发
  5. 支持视图导航
  6. 支持Windows Phone和Silverlight平台

Caliburn.Micro 的Github网址:https://github.com/Caliburn-Micro/Caliburn.Micro

image.png

Caliburn.Micro 官网:https://caliburnmicro.com/
image.png

一、Caliburn.Micro的使用基于WPF的改造

1.项目介绍

  • HelloWorld:框架的搭建、容器注入相关
  • HelloWorld.Core;放置数据模型,即mvvm中的M
  • HelloWorld.ViewModels:模型视图,即VM
  • HelloWorld.Views:V,即视图

本项目是基于.Net 7 的

2.安装软件包

PM> Install-Package Caliburn.Micro.Start

image.png

3.改造App启动项目

1、清除 App.xaml.cs 文件

using System.Windows;

namespace HelloWorld
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
    }
}

image.png

2、将 AppBoostrapper 添加到 App.xaml 的资源部分

<Application x:Class="HelloWorld.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:HelloWorld">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary>
                    <local:Startup x:Key="startup" />
                </ResourceDictionary>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

image.png

4.BootstrapperBase启动类

public class Startup : BootstrapperBase
{
    SimpleContainer _container;
    public Startup()
    {
        Initialize();
    }
    //配置类
    protected override void Configure()
    {
        //这里容器采用了CM自带的SimpleContainer,并把窗口管理器和事件聚合器注册到了容器中
        _container = new SimpleContainer()
            .Singleton<IWindowManager, WindowManager>()
            .Singleton<IEventAggregator, EventAggregator>();
        //通过反射把下面三个程序集中vm结尾的视图模型文件注册到容器
        foreach (var asm in SelectAssemblies())
        {
            foreach (var vm in asm.GetTypes())
            {
                if (vm.Name.EndsWith("VM"))
                {
                    _container.RegisterPerRequest(vm, null, vm);
                }
            }
        }
        //自定义了一套CM的VM和V的匹配规则
        //1.默认的规则是是:视图以View结尾、视图模型以ViewModel结尾
        //2.实际规则是视图模型以VM结尾,视图只要前缀和视图模型的一致就行
        var myRule = new TypeMappingConfiguration
        {
            ViewModelSuffix = "VM",
            ViewSuffixList = new() { "" }
        };

        ViewLocator.ConfigureTypeMappings(myRule);
        ViewModelLocator.ConfigureTypeMappings(myRule);
    }
    //启动类
    protected override void OnStartup(object sender, StartupEventArgs e)
    {
        base.OnStartup(sender, e);
        //设置启动视图模型
        DisplayRootViewForAsync<IndexVM>();
    }
    /// <summary>
    /// 选择程序集
    /// </summary>
    /// <returns></returns>
    protected override IEnumerable<Assembly> SelectAssemblies()
    {
        return new List<Assembly>
        {
            Assembly.Load("HelloWorld"),
            Assembly.Load("HelloWorld.Views"),
            Assembly.Load("HelloWorld.ViewModels"),
        };
    }
    /// <summary>
    /// 获取实例
    /// </summary>
    /// <param name="service"></param>
    /// <param name="key"></param>
    /// <returns></returns>
    protected override object GetInstance(Type service, string key)
    {
        return _container.GetInstance(service, key);
    }
}

5.视图和视图模型详解

继承类说明:

  • Screen 和 INotifyPropertyChanged (用于感知并同步所绑定属性的变化)
  • IHandle<BusyMessage>:IHandle<BusyMessage>

5.1 index

image.png

5.1.1 视图模型

public class IndexVM : Screen, IHandle<BusyMessage>
{
    private readonly IEventAggregator _eventAggregator;

    public IndexVM(IEventAggregator eventAggregator)
    {
        _eventAggregator = eventAggregator;
        InitVM();
    }

    public string AboutTitle { get; set; }
    public int BarValue { get; set; }
    //通过ioc容器获取VM:
    public LoginVM LoginVM { get; set; } = IoC.Get<LoginVM>();
    public TableVM TableVM { get; set; } = IoC.Get<TableVM>();

    public string MainName { get; set; } = "一种类似vue的使用方式,抛砖引玉";


    public void AboutBtn1()
    {
        MessageBox.Show("Test AboutBtn1");
    }

    //接收事件更新进度条:
    public Task HandleAsync(BusyMessage message, CancellationToken cancellationToken)
    {
        if (message.IsBusy)
        {
            BarValue = 50;
        }
        else
        {
            BarValue = 0;
        }
        return Task.CompletedTask;
    }

    protected virtual void InitVM()
    {
        AboutTitle = "测试AboutPage 绑定父作用域";

        _eventAggregator.SubscribeOnUIThread(this);
    }
}

5.1.2 视图

/// <summary>
/// Index.xaml 的交互逻辑
/// </summary>
public partial class Index : Window
{
    public Index()
    {
        InitializeComponent();
    }
}
<Window x:Class="HelloWorld.Views.Areas.Home.Index"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:home="clr-namespace:HelloWorld.Views.Areas.Home"
             xmlns:account="clr-namespace:HelloWorld.Views.Areas.Account"
             xmlns:cal="http://caliburnmicro.com"
             xmlns:fa="http://schemas.awesome.incremented/wpf/xaml/fontawesome.sharp"
             Title="{Binding MainName}"
             mc:Ignorable="d" Width="800" Height="600"
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="30" />
        </Grid.RowDefinitions>
        <TabControl TabStripPlacement="Left">
            <TabItem>
                <TabItem.Header>
                    <StackPanel>
                        <fa:IconBlock Icon="Table" FontSize="24" />
                        <TextBlock>Table</TextBlock>
                    </StackPanel>
                </TabItem.Header>
                <home:Table cal:Bind.ModelWithoutContext="{Binding}" DataContext="{Binding TableVM}" />
            </TabItem>
            <TabItem>
                <TabItem.Header>
                    <StackPanel>
                        <fa:IconBlock Icon="CircleInfo" FontSize="24" />
                        <TextBlock>About</TextBlock>
                    </StackPanel>
                </TabItem.Header>
                <home:About cal:Bind.Model="{Binding}" DataContext="{Binding}" />
            </TabItem>
            <TabItem>
                <TabItem.Header>
                    <StackPanel>
                        <fa:IconBlock Icon="UserCircle" FontSize="24" />
                        <TextBlock>Login</TextBlock>
                    </StackPanel>
                </TabItem.Header>
                <account:Login cal:Bind.ModelWithoutContext="{Binding}" DataContext="{Binding LoginVM}" />
            </TabItem>
        </TabControl>

        <ProgressBar Grid.Row="1" Value="{Binding BarValue}" Minimum="0" Maximum="100" />
    </Grid>
</Window>

因为About是绑定Index所以公用事件和变量

<UserControl x:Class="HelloWorld.Views.Areas.Home.About"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:local="clr-namespace:HelloWorld.Views.Areas.Home"

             mc:Ignorable="d"
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <StackPanel Margin="30">
            <TextBlock FontSize="20">
                <Run Text="Title:" />
                <Run Text="{Binding AboutTitle}" />
            </TextBlock>
            <Button x:Name="AboutBtn1" >测试按钮</Button>
        </StackPanel>
    </Grid>
</UserControl>

image.png

5.2 Login

image.png

注意以下代码是它通过load函数接在view

cal:Message.Attach="[Event Loaded]=[Loaded($view,$eventArgs)]"

public void Loaded(UserControl control, RoutedEventArgs @event)
{
    Debug.WriteLine(control);
    Debug.WriteLine(@event);
}

5.2.1 视图模型

public class LoginVM : Screen
{
    private readonly IEventAggregator _eventAggregator;

    public LoginVM(IEventAggregator eventAggregator)
    {
        _eventAggregator = eventAggregator;
    }

    public string Password { get; set; } = "123";
    public string UserName { get; set; } = "王小虎";

    public async Task DoLogin()
    {
        await _eventAggregator.PublishOnBackgroundThreadAsync(new BusyMessage(true));

        await Task.Delay(1000);
        MessageBox.Show("Test Login Success");

        await _eventAggregator.PublishOnBackgroundThreadAsync(new BusyMessage(false));
    }

    public void Loaded(UserControl control, RoutedEventArgs @event)
    {
        Debug.WriteLine(control);
        Debug.WriteLine(@event);
    }
}

5.2.2 视图

<UserControl x:Class="HelloWorld.Views.Areas.Account.Login"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:local="clr-namespace:HelloWorld.Views.Areas.Account"
             xmlns:cal="http://caliburnmicro.com"
             cal:Message.Attach="[Event Loaded]=[Loaded($view,$eventArgs)]"
             mc:Ignorable="d"
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <StackPanel Margin="50">
            <TextBlock FontSize="24">测试组件绑定自己的vm作用域</TextBlock>
            <DockPanel Margin="0 10">
                <Label Width="100">用户名:</Label>
                <TextBox x:Name="UserName" />
            </DockPanel>

            <DockPanel Margin="0 10">
                <Label Width="100">密码:</Label>
                <TextBox x:Name="Password" />
            </DockPanel>

            <Button x:Name="DoLogin" Width="120">Login</Button>
        </StackPanel>
    </Grid>
</UserControl>

5.3 Login

image.png

5.3.1 视图模型

public class TableVM : Screen
{
    private List<Foo> _data = new();

    public TableVM()
    {
        InitData();
    }

    public ObservableCollection<Foo> Data { get; set; }

    public bool IsShow { get; set; }

    public void Loaded()
    {
        IsShow = true;
    }

    public void Unloaded()
    {
        IsShow = false;
    }

    private void InitData()
    {
        Task.Run(async () =>
        {
            while (true)
            {
                if (IsShow)
                {
                    _data.Add(new Foo
                    {
                        Id = Guid.NewGuid(),
                        Name = "John" + new Random().Next(1, 100),
                        School = "上海大学"
                    });
                    Data = new ObservableCollection<Foo>(_data);
                }

                await Task.Delay(1000);
            }
        });
    }
}
/// <summary>
/// 核心模型或许来自网站项目的
/// </summary>
[AddINotifyPropertyChangedInterface]
public class Foo : HelloWorld.Core.Models.Foo
{
}

5.3.2 视图

<UserControl x:Class="HelloWorld.Views.Areas.Home.Table"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:HelloWorld.Views.Areas.Home"
             xmlns:cal="http://caliburnmicro.com"
             cal:Message.Attach="[Event Loaded]=[Loaded];[Event Unloaded]=[Unloaded]"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <DataGrid ItemsSource="{Binding Data}" IsReadOnly="True"/>
    </Grid>
</UserControl>

源码下载:https://download.csdn.net/download/aa2528877987/87459517

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。