棱镜事件聚合器。加载模块时发布事件
Prism EventAggregator. Publishing event while loading modules
我想跟踪已加载模块的总数,以便用户可以看到剩余的加载量。所以我决定单独加载每个模块,然后发布一个事件。
我可以看到订阅者被击中并且 运行 通过所有正确的代码,但是 UI 在所有模块都被加载之前不会更新。所以我的进度条直接从 0 到 100。
所以澄清一下,我遇到的问题是 UI 似乎在整个模块加载过程中都被冻结了。有什么办法可以解决这个问题,以便我可以使用进度条吗?
引导程序
{
protected override void InitializeModules()
{
FillModuleCatalogFromConfig();
// begin the initialization process
eventAggregator = this.Container.Resolve<IEventAggregator>();
eventAggregator.GetEvent<BeginLoadingModulesEvent>().Publish(true);
// load the rest of the modules
InitializeRemainingModules();
eventAggregator.GetEvent<BeginLoadingModulesEvent>().Publish(false);
}
private void InitializeRemainingModules()
{
foreach (var module in ModuleCatalog.Modules)
{
InitializeModule(module);
}
}
private void InitializeModule(ModuleInfo moduleInfo)
{
if (moduleInfo.State == ModuleState.Initialized)
return;
if (moduleInfo.DependsOn.Count > 0)
{
// Load any dependencies first
foreach (var dependenciesModulesName in moduleInfo.DependsOn)
{
// if the dependency isn't loaded then we'll have to load that first
ModuleInfo module = ModuleCatalog.Modules.First(x => x.ModuleName == dependenciesModulesName);
if (module.State != ModuleState.Initialized)
{
// must initialize this module first
InitializeModule(module);
}
}
}
eventAggregator.GetEvent<MyEvent>().Publish(new ProgressChangedEventArgs(CalculateModulesLoadedProgress(), moduleInfo.ModuleName));
moduleManager.LoadModule(moduleInfo.ModuleName);
}
private int CalculateModulesLoadedProgress()
{
decimal progress = Decimal.Divide(ModuleCatalog.Modules.Where(x => x.State == ModuleState.Initialized).Count(), ModuleCatalog.Modules.Count()) * 100;
return (int)(Math.Round(progress));
}
}
ViewModel到显示进度条的shell
public Class ShellViewModel
{
IEventAggregator ea;
ShellViewModel(IEventAggregator ea)
{
this.ea = ea;
this.ea.GetEvent<MyEvent>().Subscribe(this.UpdateProgressBar);
}
public int ProgressValue
{
get { return progressValue; }
set { SetProperty(ref progressValue, value); }
}
private void UpdateProgressBar(ProgressChangedEventArgs args)
{
// this all gets hit and runs fine, but the actual UI bar for progress
// wont get hit until all modules are done loading
this.ProgressValue = args.ProgressPercentage;
}
}
我不认为我会为此使用 EventAggregator
我认为我会使用带有进度 window 的常规事件来显示如下内容:
public sealed class ProgressEvent
{
public EventHandler AddModule;
private static ProgressEvent _instance = new ProgressEvent();
public static ProgressEvent GetInstance()
{
return _instance;
}
public void OnAddModule(object sender, EventArgs e)
{
var addModuleDelegate = AddModule as EventHandler;
if(addModuleDelegate != null)
{
addModuleDelegate.Invoke(sender, e);
}
}
}
和模块内部:
public void Initialize()
{
//do work here
ProgressEvent.GetInstance().OnAddModule(this, new EventArgs());
}
像这样注册:
public Progressbar()
{
InitializeComponent();
ProgressEvent.GetInstance().AddModule += AddProgress;
}
您绝对需要在单独的线程上加载。
列表Task.Run(()=> load modules);
我确实弄明白了。或者至少按照我想要的方式工作。我刚刚使用了 Dispatcher 并将其设置为后台优先级。
而不是
moduleManager.LoadModule(moduleInfo.ModuleName);
我用过
Application.Current.Dispatcher.Invoke(() => moduleManager.LoadModule(moduleInfo.ModuleName), DispatcherPriority.Background);
我想跟踪已加载模块的总数,以便用户可以看到剩余的加载量。所以我决定单独加载每个模块,然后发布一个事件。
我可以看到订阅者被击中并且 运行 通过所有正确的代码,但是 UI 在所有模块都被加载之前不会更新。所以我的进度条直接从 0 到 100。
所以澄清一下,我遇到的问题是 UI 似乎在整个模块加载过程中都被冻结了。有什么办法可以解决这个问题,以便我可以使用进度条吗?
引导程序
{
protected override void InitializeModules()
{
FillModuleCatalogFromConfig();
// begin the initialization process
eventAggregator = this.Container.Resolve<IEventAggregator>();
eventAggregator.GetEvent<BeginLoadingModulesEvent>().Publish(true);
// load the rest of the modules
InitializeRemainingModules();
eventAggregator.GetEvent<BeginLoadingModulesEvent>().Publish(false);
}
private void InitializeRemainingModules()
{
foreach (var module in ModuleCatalog.Modules)
{
InitializeModule(module);
}
}
private void InitializeModule(ModuleInfo moduleInfo)
{
if (moduleInfo.State == ModuleState.Initialized)
return;
if (moduleInfo.DependsOn.Count > 0)
{
// Load any dependencies first
foreach (var dependenciesModulesName in moduleInfo.DependsOn)
{
// if the dependency isn't loaded then we'll have to load that first
ModuleInfo module = ModuleCatalog.Modules.First(x => x.ModuleName == dependenciesModulesName);
if (module.State != ModuleState.Initialized)
{
// must initialize this module first
InitializeModule(module);
}
}
}
eventAggregator.GetEvent<MyEvent>().Publish(new ProgressChangedEventArgs(CalculateModulesLoadedProgress(), moduleInfo.ModuleName));
moduleManager.LoadModule(moduleInfo.ModuleName);
}
private int CalculateModulesLoadedProgress()
{
decimal progress = Decimal.Divide(ModuleCatalog.Modules.Where(x => x.State == ModuleState.Initialized).Count(), ModuleCatalog.Modules.Count()) * 100;
return (int)(Math.Round(progress));
}
}
ViewModel到显示进度条的shell
public Class ShellViewModel
{
IEventAggregator ea;
ShellViewModel(IEventAggregator ea)
{
this.ea = ea;
this.ea.GetEvent<MyEvent>().Subscribe(this.UpdateProgressBar);
}
public int ProgressValue
{
get { return progressValue; }
set { SetProperty(ref progressValue, value); }
}
private void UpdateProgressBar(ProgressChangedEventArgs args)
{
// this all gets hit and runs fine, but the actual UI bar for progress
// wont get hit until all modules are done loading
this.ProgressValue = args.ProgressPercentage;
}
}
我不认为我会为此使用 EventAggregator
我认为我会使用带有进度 window 的常规事件来显示如下内容:
public sealed class ProgressEvent
{
public EventHandler AddModule;
private static ProgressEvent _instance = new ProgressEvent();
public static ProgressEvent GetInstance()
{
return _instance;
}
public void OnAddModule(object sender, EventArgs e)
{
var addModuleDelegate = AddModule as EventHandler;
if(addModuleDelegate != null)
{
addModuleDelegate.Invoke(sender, e);
}
}
}
和模块内部:
public void Initialize()
{
//do work here
ProgressEvent.GetInstance().OnAddModule(this, new EventArgs());
}
像这样注册:
public Progressbar()
{
InitializeComponent();
ProgressEvent.GetInstance().AddModule += AddProgress;
}
您绝对需要在单独的线程上加载。
列表Task.Run(()=> load modules);
我确实弄明白了。或者至少按照我想要的方式工作。我刚刚使用了 Dispatcher 并将其设置为后台优先级。
而不是
moduleManager.LoadModule(moduleInfo.ModuleName);
我用过
Application.Current.Dispatcher.Invoke(() => moduleManager.LoadModule(moduleInfo.ModuleName), DispatcherPriority.Background);