(十四)数据加载动画
1. 需求:需要等待加载时的画面
思路在主页MainView的dialoghost中显示一个dialogcontent
- 创建类更新加载事件
![image]()
![image]()
- 创建一个viewmodel
为了todoviewmodel拥有加载弹窗这个功能,新建这个基类(这个基类继承BindableBase,然后todoviewmodel继承这个基类)
![image]()
2. 补充知识点:事件聚合器EventAggregator
在 MVVM 中,对于 View 和 ViewModel 之间的交互,可以使用 INotifyProperty 和 ICommand 来实现。而对于不同 ViewModel 之间的通信,为了实现低耦合,Prism 提供了EventAggregator。
EventAggregator 是基于事件聚合器服务,允许发布者和订阅者之间通过事件进行通讯,且彼此之间没有直接引用。

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. 加载弹窗的新建过程
NavigationViewModel
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();
}










浙公网安备 33010602011771号