Prism EventAggregator。加载模块时发布事件

时间:2017-10-16 16:03:01

标签: c# wpf multithreading prism eventaggregator

我想跟踪已加载的模块数量,以便用户可以看到剩余的加载量。所以我决定单独加载每个模块然后发布一个事件。

我可以看到订阅者正在点击并运行所有正确的代码,但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;
    }
}

2 个答案:

答案 0 :(得分:1)

我最终确定了这一点。或者至少以我想要的方式工作。我刚刚使用Dispatcher并将其设置为后台优先级。

而不是

moduleManager.LoadModule(moduleInfo.ModuleName);

我用过

Application.Current.Dispatcher.Invoke(() => moduleManager.LoadModule(moduleInfo.ModuleName), DispatcherPriority.Background);

答案 1 :(得分:0)

我不认为我会使用EventAggregator这样我认为我会使用带有“进度”窗口的常规事件来显示如下内容:

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);