Wpf 使用 Prism 实战开发Day18

数据加载动画实现

概要:

当打开功能页面时,在数据未加载完毕前,希望有一个友好的等待提示。那么,本章通过学习Prism 中事件聚合器(EventAggregator),并通过创建等待提示窗口,同时结合事件订阅发布来实现该功能点。


一.事件聚合器(EventAggregator)实现发布和订阅

1.定义事件消息模型

 定义一个 UpdateLoadingEvent (等待加载完成的事件)消息模型,并继承PubSubEvent。PubSubEvent 是一个泛型,可以传入字符串或其他。如下传入一个UpdateModel 实体类。表明了当前的消息模型用来传递一个对象实体类的消息或定义成一个string (字符串) 表示传递一个字符串的消息。

传递对象实体类消息

    public class UpdateModel
    {
        public bool IsOpen { get; set; }
    }
    public class UpdateLoadingEvent:PubSubEvent<UpdateModel>
    {

    }

传递字符串消息

public class UpdateLoadingEvent:PubSubEvent<string>
{

}

2.发布事件 

如何使用:在构造函数中注入IEventAggregator,并通过IEventAggregatorGetEvent获取定义的UpdateLoadingEvent 消息,再通过Publish 方法进行发布消息。

当前发布事件主要用来,处理某个View 或ViewMode 之间传递消息,则使用 Publish 来进行发布一个消息

/// <summary>
/// 发布事件
/// </summary>
/// <param name="aggregator"></param>
 /// <param name="model"></param>
public UpdateLoading(IEventAggregator aggregator,UpdateModel model)
{
    aggregator.GetEvent<UpdateLoadingEvent>().Publish(model);
}

3.订阅事件

如何使用:在构造函数中注入IEventAggregator,并通过IEventAggregatorGetEvent获取定义的UpdateLoadingEvent 消息,再通过Subscribe方法注册,Subscribe是一个委托方法

/// <summary>
/// 订阅事件
/// </summary>
/// <param name="aggregator"></param>
/// <param name="model"></param>
public UpdateLoading(IEventAggregator aggregator,Action<UpdateModel> model)
{
   aggregator.GetEvent<UpdateLoadingEvent>().Subscribe(model);
}

一种写法

/// <summary>
/// 订阅事件
/// </summary>
/// <param name="aggregator"></param>
/// <param name="model"></param>
public UpdateLoading(IEventAggregator aggregator)
{
   aggregator.GetEvent<UpdateLoadingEvent>().Subscribe(arg=>
   {
     // arg 就是订阅到的消息,进行逻辑处理
   });
}

 一种写法

/// <summary>
/// 订阅事件
/// </summary>
/// <param name="aggregator"></param>
/// <param name="model"></param>
public UpdateLoading(IEventAggregator aggregator)
{
   aggregator.GetEvent<UpdateLoadingEvent>().Subscribe(SubMessage);
}
private void SubMessage(UpdateModel model)
{
  //逻辑处理
}

 无论是那种写法,订阅事件都是需要传入一个委托。并且只有订阅了相关消息模型后,从其他View 或ViewMode 发布的消息,才能成功接收到。一般,订阅消息,也称注册消息,都是干同一件事件。

4.取消订阅

Unsubscribe 同样也是一个委托方法。事件订阅被取消后,无论再怎么发布该事件,都无法接收到该事件消息了。

/// <summary>
/// 发布事件
/// </summary>
/// <param name="aggregator"></param>
/// <param name="model"></param>
public UpdateLoading(IEventAggregator aggregator)
{
aggregator.GetEvent<UpdateLoadingEvent>().Unsubscribe(SubMessage);
}

这样,一个发布/订阅/取消事件的例子就完成了。上面只是说明Prism 事件聚合器的使用例子。表示怎么定义事件模型,以及使用事件模型。有了上面的基础后,接着实现根据事件聚合器实现数据加载等待窗口功能。


二.实现数据加载等待窗口功能

当打开待办事项或备忘录数据窗口时,在数据未准备完成前,显示一个加载中的提示消息窗口。

首先是要在MainView 中,定义一个名字:DialogHost

1.然后要在Views 文件夹中定义加载中视图窗口 (ProgressView.xaml)

<UserControl x:Class="MyToDo.Views.ProgressView"
             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:MyToDo.Views"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <StackPanel Width="80">
            <ProgressBar Width="40" Height="40" IsIndeterminate="True" Margin=" 20"
                         Style="{StaticResource MaterialDesignCircularProgressBar}"
                         />
        </StackPanel>
    </Grid>
</UserControl>

2.定义打开窗口的消息模型

创建一个 Events 文件夹,定义一个 UpdateLoadingEvent (等待加载完成的事件)消息模型。并且定义一个实体类 UpdateModel ,实体类有一个IsOpen属性,表示窗口是否打开状态。把该实体类传入泛型对象PubSubEvent 中。

namespace MyToDo.Common.Events
{
    public class UpdateModel
    {
        public bool IsOpen { get; set; }
    }
    public class UpdateLoadingEvent:PubSubEvent<UpdateModel>
    {

    }
}

3.创建一个基类 NavigationViewModel

封装一个基类(共用类) NavigationViewModel,该类的主要作用是可以设置窗口的等待,就是它需要等待我们数据加载完成,才能展示出对应的数据窗口。它同时具备导航功能,需要转到对应的数据页面。且需要继承INavigationAware。该基类的方法,增加 virtual,表示它是一个虚方法,表明其他继承基类的子类也能修改基类方法。

创建一个基类(NavigationViewModel)这里,有点绕。就是例如:待办事项页面,需要等待数据加载完成。那么我们就需要把这个待办事项页面设置成可等待窗口,同时显示加载中的效果。所以就需要这么去创建一个基类,同时其他页面也能沿用该基类。

然后在基类构造函数中通过 IOC 容器(IContainerProvider) ,注册事件聚合器,并拿到IEventAggregator 的实例。再通过IEventAggregator 去发布消息,设置页面要展示的加载中的效果。

NavigationViewModel 类

namespace MyToDo.ViewModels
{
    public class NavigationViewModel : BindableBase, INavigationAware
    {
        private readonly IContainerProvider containerProvider;
        public readonly IEventAggregator aggregator;
        public NavigationViewModel(IContainerProvider containerProvider)
        {
            this.containerProvider = containerProvider;
            aggregator=containerProvider.Resolve<IEventAggregator>();
        }
        /// <summary>
        /// 重用以前窗口
        /// </summary>
        /// <param name="navigationContext"></param>
        /// <returns></returns>
        public virtual bool IsNavigationTarget(NavigationContext navigationContext)
        {
            return true;
        }

        public virtual void OnNavigatedFrom(NavigationContext navigationContext)
        {
            
        }

        public virtual void OnNavigatedTo(NavigationContext navigationContext)
        {
            
        }

        /// <summary>
        /// 发布消息
        /// </summary>
        /// <param name="IsOpen">是否打开窗口</param>
        public void UpdateLoading(bool IsOpen)
        {
            aggregator.UpdateLoading(new Common.Events.UpdateModel()
            {
                IsOpen = IsOpen
            });
        }
    }
}

然后接着实现IEventAggregator 事件的发布/订阅 。目前考滤是把发布和订阅,做成一个扩展类,可供NavigationViewModel 或MainView 使用。或其他view中需要使用到发布订阅都可以用到该扩展。

namespace MyToDo.Extensions
{
    public static class DialogExtensions
    {
        /// <summary>
        /// 发布事件
        /// </summary>
        /// <param name="aggregator"></param>
        /// <param name="model"></param>
        public static void UpdateLoading(this IEventAggregator aggregator,UpdateModel model)
        {
            aggregator.GetEvent<UpdateLoadingEvent>().Publish(model);
        }
        /// <summary>
        /// 订阅事件
        /// </summary>
        /// <param name="aggregator"></param>
        /// <param name="model"></param>
        public static void Resgiter(this IEventAggregator aggregator,Action<UpdateModel> model)
        {
            aggregator.GetEvent<UpdateLoadingEvent>().Subscribe(model);
        }
    }
}

4.发布消息

首先:当前待办事项页面,或备忘录页面,当打开页面时,需要加载数据。那么待办事项类就需要在数据未准备好前,发布一个打开加载中的窗口的一个消息。数据渲染完成后,发布一个关闭加载中的窗口的一个消息。 

待办事项类 (ToDoViewModel)修改。

namespace MyToDo.ViewModels
{
   public class ToDoViewModel: NavigationViewModel
    {
        //由于NavigationViewModel 类构造中传入了 IOC容器,所以当前类继承的时候,需要把对应的参数传通过Base传过去就不会报错了
        public ToDoViewModel(IToDoService toDoService, IContainerProvider provider):base(provider)
        {
            ToDoDtos = new ObservableCollection<ToDoDto>();
            AddCommand = new DelegateCommand(Add);
            this.toDoService = toDoService;
        }
        private bool isRightDrawerOpen;
        /// <summary>
        /// 右侧编辑窗口是否展开
        /// </summary>
        public bool IsRightDrawerOpen
        {
            get { return isRightDrawerOpen; }
            set { isRightDrawerOpen = value; RaisePropertyChanged(); }
        }


        public DelegateCommand AddCommand{ get; private set; }
        private ObservableCollection<ToDoDto> toDoDtos;
        private readonly IToDoService toDoService;

        /// <summary>
        /// 创建数据的动态集合
        /// </summary>
        public ObservableCollection<ToDoDto> ToDoDtos
        {
            get { return toDoDtos; }
            set { toDoDtos = value;RaisePropertyChanged(); }
        }
        /// <summary>
        /// 获取数据
        /// </summary>
        async void GetDataAsync()
        {
            UpdateLoading(true); //发布消息,设置加载中的窗口
            //添加查询条件
           var todoResult=await toDoService.GetAllAsync(new Shared.Parameters.QueryParameter()
            {
                PageIndex = 0,
                PageSize = 100,
            });
            if (todoResult.Status)
            {
                toDoDtos.Clear();
                foreach (var item in todoResult.Result.Items)
                {
                    toDoDtos.Add(item);
                }
            }
            UpdateLoading(false); //发布消息,关闭加载中的窗口
        }
        /// <summary>
        /// 添加待办
        /// </summary>
        /// <exception cref="NotImplementedException"></exception>
        private void Add()
        {
            IsRightDrawerOpen=true;
        }

        //重写导航加载数据的方法
        public override void OnNavigatedTo(NavigationContext navigationContext)
        {
            base.OnNavigatedTo(navigationContext);
            GetDataAsync();
        }
    }
}

5.MainView 消息订阅

最后:当消息发布后,谁要订阅到这个消息?并进行对应的打开或关闭加载中的窗口逻辑处理?那就是要在 MainView中订阅,传递过来的消息是否要打开加载中的窗口(ProgressView.xaml)或关闭加载中的窗口(ProgressView.xaml)。所以需要在MainView中去实现该功能逻辑

namespace MyToDo.Views
{
    /// <summary>
    /// MainView.xaml 的交互逻辑
    /// </summary>
    public partial class MainView : Window
    {
        public MainView(IEventAggregator aggregator)
        {
            InitializeComponent();
            //订阅是否打开或关闭加载中的窗口
            aggregator.Resgiter(arg =>
            {
                DialogHost.IsOpen = arg.IsOpen;//设置打开窗口
                if (DialogHost.IsOpen)
                {
                    DialogHost.DialogContent = new ProgressView();
                }
            });
        }
    }
}

三.最后项目结构

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

asp.net core 网页接入微信扫码登录

创建微信开放平台账号&#xff0c;然后创建网页应用 获取appid和appsecret 前端使用的vue&#xff0c;安装插件vue-wxlogin 调用代码 <wxlogin :appid"appId" :scope"scope" :redirect_uri"redirect_uri"></wxlogin> <scri…

日本发现上百例食用功能性标示食品后健康受损案例

据央视新闻&#xff0c;日本消费者厅12日说&#xff0c;受小林制药公司含红曲成分问题保健品事件影响&#xff0c;他们对数千种功能性标示食品实施了紧急检查&#xff0c;发现上百例消费者健康受损案例。 小林制药问题保健品事件曝光后&#xff0c;日本消费者厅对所有备案过的…

(2024,IXC2-4KHD,LVLM,动态图像分割,高分辨率图像处理)InternLM-XComposer2-4KHD

InternLM-XComposer2-4KHD: A Pioneering Large Vision-Language Model Handling Resolutions from 336 Pixels to 4K HD 公和众和号&#xff1a;EDPJ&#xff08;进 Q 交流群&#xff1a;922230617 或加 VX&#xff1a;CV_EDPJ 进 V 交流群&#xff09; 目录 0. 摘要 3. 方…

排序算法之快速排序

目录 一、简介二、代码实现三、应用场景 一、简介 算法平均时间复杂度最好时间复杂度最坏时间复杂度空间复杂度排序方式稳定性快速排序O( N N N log ⁡ 2 N \log_{2}N log2​N)O( N N N log ⁡ 2 N \log_{2}N log2​N)O(n^2)O( log ⁡ 2 N \log_{2}N log2​N)In-place不稳定 稳…

llamafactory:unified efficient fine-tuning of 100+ lanuage models

1.introduction llamafactory由三个主要模块组成&#xff0c;Model Loader&#xff0c;Data Worker&#xff0c;Trainer。 2.Efficient fine-tuning techniques 2.1 Efficient Optimization 冻结微调&#xff1a;冻结大部分参数&#xff0c;同时只在一小部分解码器层中微调剩…

算法1: 素数个数统计

统计n以内的素数个数 素数&#xff1a;只能被1和自身整除的自然数&#xff0c;0和1除外&#xff1b; 举例&#xff1a; 输入&#xff1a;100 输出&#xff1a;25 import java.util.*; class Test1{public static void main(String[] args){int a 100; //输入数字//…

Golang教程一(环境搭建,变量,数据类型,数组切片map)

目录 一、环境搭建 1.windows安装 2.linux安装 3.开发工具 二、变量定义与输入输出 1.变量定义 2.全局变量与局部变量 3.定义多个变量 4.常量定义 5.命名规范 6.输出 格式化输出 7.输入 三、基本数据类型 1.整数型 2.浮点型 3.字符型 4.字符串类型 转义字…

Linux/October

October Enumeration Nmap 扫描发现对外开放了22和80端口&#xff0c;使用nmap详细扫描这两个端口 ┌──(kali㉿kali)-[~/vegetable/HTB/October] └─$ nmap -sC -sV -p 22,80 -oA nmap 10.10.10.16 Starting Nmap 7.…

SLA——让你的信息更安全

在单一的静态密码登录验证机制下&#xff0c;非法入侵者若窃听到Windows桌面登录账号的用户名和密码&#xff0c;便可通过合法权限访问内部系统&#xff0c;此时企业信息安全将面临严峻挑战。 企业为了防止账号信息泄露&#xff0c;通常会强制要求员工定期更换登录密码&#x…

java下载网络上的文件、图片保存到本地 FileUtils

java下载网络上的文件、图片保存到本地 FileUtils 1. 引入FileUtils依赖2. 实现代码3. 输出结果 1. 引入FileUtils依赖 <!--FileUtils依赖--> <!-- https://mvnrepository.com/artifact/commons-io/commons-io --> <dependency><groupId>commons-io&l…

Linux文本编辑器vim使用和分析—6

目录 1.对vim的简单理解&#xff1a; 2.看待vim的视角&#xff1a; 3.命令模式&#xff1a; 3.1vim被打开后默认的模式&#xff1a; 3.2命令模式切换插入模式&#xff1a; 3.3其他模式回到命令模式&#xff1a; 3.4光标定位&#xff1a; 4.插入模式(编辑模式)&#xff1…

【从浅学到熟知Linux】程序地址空间分布与进程地址空间详谈(含虚拟地址到物理地址的映射)

&#x1f3e0;关于专栏&#xff1a;Linux的浅学到熟知专栏用于记录Linux系统编程、网络编程等内容。 &#x1f3af;每天努力一点点&#xff0c;技术变化看得见 文章目录 程序地址空间概览进程地址空间 程序地址空间概览 我们在执行一个C语言程序时&#xff0c;它包含代码、变量…

【Canvas与艺术】绘制灰白黑鱼鳞纹“Premium Quality”标志

【关键点】 环状鱼鳞纹的制作 【成果图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>灰白黑鱼鳞纹Premium Quality标志&…

Linux ARM平台开发系列讲解(QEMU篇) 1.2 新添加一个Linux kernel设备树

1. 概述 上一章节我们利用QEMU成功启动了Linux kernel,但是细心的小伙伴就会发现,我们用默认的defconfig是没有找到设备树源文件的,但是又发现kernel启动时候它使用了设备树riscv-virtio,qemu,这是因为qemu用了一个默认的设备树文件,该章节呢我们就把这个默认的设备树文件…

12-LINUX--进程间的通信

进程间通信&#xff1a;采用IPC机制&#xff08;进程间的用户空间相互独立&#xff0c;内核空间共享&#xff09;&#xff0c;有管道&#xff0c;信号量&#xff0c;共享内存&#xff0c;消息队列&#xff0c;套接字。 一.管道 管道可以用来在两个进程之间传递数据&#xff0c…

Java8 收集Stream流中的结果

目录 Stream流中的结果到集合中 Stream流中的结果到数组中 对流中数据进行聚合计算 1. 获取最大值 2. 获取最小值 3. 求总和 4. 平均值 5. 统计数量 对流中数据进行分组 对流中数据进行多级分组 对流中数据进行分区 对流中数据进行拼接 Stream流中的结果到集合中 …

Facebook广告投放数据API对接流程

说明&#xff1a;仅供学习使用&#xff0c;请勿用于非法用途&#xff0c;若有侵权&#xff0c;请联系博主删除 作者&#xff1a;zhu6201976 一、需求背景 App在Facebook、Google等巨头进行广告投放&#xff0c;想要拿到实时广告投放效果数据&#xff0c;如曝光、点击、花费、触…

mybatis(5)参数处理+语句查询

参数处理&#xff0b;语句查询 1、简单单个参数2、Map参数3、实体类参数4、多参数5、Param注解6、语句查询6.1 返回一个实体类对象6.2 返回多个实体类对象 List<>6.3 返回一个Map对象6.4 返回多个Map对象 List<Map>6.5 返回一个大Map6.6 结果映射6.6.1 使用resultM…

流氓软件清理绝杀全家桶

下载地址&#xff1a;流氓软件清理绝杀全家桶.zip 网上仍有不少软件中携带流氓软件&#xff0c;甚至某些所谓的大厂出品的工具中也会有一些捆绑&#xff01; 对于玩机经验不太丰富的小白来说&#xff0c;也许一不小心&#xff0c;桌面就会被某些流氓软件搞得乌烟瘴气&#xf…

【每日刷题】技巧合集-LC136、LC169

1. LC136.只出现一次的数字 题目链接 解法一&#xff1a; 先给数字排序&#xff0c;如果num[i]与nums[i-1]或nums[i1]都不一致&#xff0c;则返回nums[i]。 class Solution {public int singleNumber(int[] nums) {if (nums.length 1){return nums[0];}Arrays.sort(nums);fo…