(十四)数据加载动画

1. 需求:需要等待加载时的画面

思路在主页MainView的dialoghost中显示一个dialogcontent

  1. 创建类更新加载事件
    image
    image
  2. 创建一个viewmodel
    为了todoviewmodel拥有加载弹窗这个功能,新建这个基类(这个基类继承BindableBase,然后todoviewmodel继承这个基类)
    image

2. 补充知识点:事件聚合器EventAggregator

原文讲解

在 MVVM 中,对于 View 和 ViewModel 之间的交互,可以使用 INotifyProperty 和 ICommand 来实现。而对于不同 ViewModel 之间的通信,为了实现低耦合,Prism 提供了EventAggregator。

EventAggregator 是基于事件聚合器服务,允许发布者和订阅者之间通过事件进行通讯,且彼此之间没有直接引用。
image

IEventAggregator

EventAggregator 类在容器中是作为服务提供的,其对应的接口是 IEventAggregator.事件管理器用来定位和创建事件,其内部维护系统事件的集合。

public interface IEventAggregator { TEventType GetEvent<TEventType>() where TEventType : EventBase; }

发布事件

// 定义事件 
public class TickerSymbolSelectedEvent : PubSubEvent<string>{}
// 发布者从 EventAggregator 中检索事件并调用 Publish 方法来发布事件 
public class MainPageViewModel { 
	IEventAggregator _eventAggregator; 
	public MainPageViewModel(IEventAggregator ea)
	{ _eventAggregator = ea; }
	public void PublishEvent() { 
	// 发布事件,然后拍拍屁股走人,不用负任何责任 _eventAggregator.GetEvent<TickerSymbolSelectedEvent>().Publish("STOCK0"); } }

订阅事件

public class MainPageViewModel
{ 
	public MainPageViewModel(IEventAggregator ea) { ea.GetEvent<TickerSymbolSelectedEvent>().Subscribe(ShowNews); } 
	void ShowNews(string companySymbol) { //implement logic } }

订阅者在订阅事件的时候,可以根据不同需求来适当调整接收参数:

•线程调度 - 如果收到事件时需要更新UI元素,可以配置接收方法在UI线程上执行•事件过滤 - 可以在订阅时提供过滤委托来过滤事件•强引用 - 如果对事件有性能问题,可以在订阅时使用强引用委托,然后手动取消•默认 - 如果上述都不适用,请使用默认订阅

订阅UI线程

默认情况下,订阅者在发布者的线程上接收事件。如果订阅者需要更新UI元素,在WPF中只有UI线程才可以更新UI元素,需要在订阅时指定线程。

public MainPageViewModel(IEventAggregator ea) { ea.GetEvent<TickerSymbolSelectedEvent>().Subscribe(ShowNews, ThreadOption.UIThread); }

参数 ThreadOption 还有其他可选项:

•PublisherThread- 默认值,在发布者线程上接收事件•BackgroundThread- 在线程池上接收事件•UIThread- 在UI线程上接收事件

过滤事件

通常,订阅者不需要处理发布事件的每个实例,这时候需要订阅者使用过滤参数。

public class MainPageViewModel 
{ 
	public MainPageViewModel(IEventAggregator ea) { TickerSymbolSelectedEvent tickerEvent = ea.GetEvent<TickerSymbolSelectedEvent>(); 
	// 通常,此过滤器作为 lambda 表达式;false表示不是强引用 tickerEvent.Subscribe(ShowNews, ThreadOption.UIThread, false, companySymbol => companySymbol == "STOCK0"); } void ShowNews(string companySymbol) { //implement logic } }

强委托引用

如果在短时间内引发多个事件并担心性能问题,可以指定强委托引用。

•true - 事件实例保持对订阅者实例的强引用,不允许订阅者被垃圾回收•false - 默认值,当订阅者被垃圾回收时,该事件自动取消订阅

退订事件

public class MainPageViewModel
{ 
	TickerSymbolSelectedEvent _event; public MainPageViewModel(IEventAggregator ea) 
	{ _event = ea.GetEvent<TickerSymbolSelectedEvent>(); _event.Subscribe(ShowNews); }
	void Unsubscribe() { _event.Unsubscribe(ShowNews); }
	void ShowNews(string companySymbol) { //implement logic } }。

3. 加载弹窗的新建过程

public class NavigationViewModel :BindableBase, INavigationAware
{//具备基类导航功能
    private readonly IContainerProvider containerProvider;
    public readonly IEventAggregator aggregator;//通过它调用方法去控制main view来展开dialogcontent
    //要拿到容器
    public NavigationViewModel(IContainerProvider containerProvider)
    {
        this.containerProvider = containerProvider;
        //从容器当中拿到这个实例
        aggregator=containerProvider.Resolve<IEventAggregator>();
    }
    public virtual bool IsNavigationTarget(NavigationContext navigationContext)
    {//是否重用以前的窗口   
        return true;
    }
    //如果viewmodel中想要修改这一状态就设置为虚方法virtual
    public virtual void OnNavigatedFrom(NavigationContext navigationContext)
    {           
    }

    public virtual void OnNavigatedTo(NavigationContext navigationContext)
    {         //在ToDoViewModel重写这个方法切换到弹窗页面
    }

    //用于展开窗口
    public void UpdateLoading(bool IsOpen)//是否打开窗口
    {
        aggregator.UpdateLoading(new Common.Events.UpdateModel()
        {
            IsOpen = IsOpen
        });
    }
}

扩展类

 public static class DialogExtensions
 {//写扩展方法,用于支持弹窗

     //推送等待消息
     public static void UpdateLoading(this IEventAggregator aggregator,UpdateModel model)
     {
         aggregator.GetEvent<UpdateLoadingEvent>().Publish(model);
         //获取UpdateLoadingEvent这个发布事件,推送消息model控制是否展开的类
     }  

     //注册等待消息
     public static void Register(this IEventAggregator aggregator,Action<UpdateModel> action)//委托
     {
         aggregator.GetEvent<UpdateLoadingEvent>().Subscribe(action);//订阅
     }
 }

修改原本的类

  • 给dialoghost加个名字
    image

  • 新建一个用户控件:就是加载页面(样式用md的)
    image

  • 在mainview中注册这个窗口页面
    image

  • NavigationViewModel中要有这个方法
    image

  • ToDoViewModel
    构造方法要修改
    image
    这两个方法要修改

 //获取数据
 async void GetDataAsync()
 {
     //打开加载数据页面
     UpdateLoading(true);
     var todoResult = await service.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);
 }
 //重写导航加载数据的方法
 public override void OnNavigatedTo(NavigationContext navigationContext)
 {
     base.OnNavigatedTo(navigationContext);
     GetDataAsync();
 }
posted @ 2023-10-10 15:15  huihui不会写代码  阅读(106)  评论(0)    收藏  举报