【问题标题】:Prism EventAggregator. Publishing event while loading modules棱镜事件聚合器。加载模块时发布事件
【发布时间】:2017-10-16 16:03:01
【问题描述】:

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

我可以看到订阅服务器正在运行并运行所有正确的代码,但在加载所有模块之前,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;
    }
}

【问题讨论】:

    标签: c# wpf multithreading prism eventaggregator


    【解决方案1】:

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

    代替

    moduleManager.LoadModule(moduleInfo.ModuleName);
    

    我用过

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

    【讨论】:

      【解决方案2】:

      我不认为我会为此使用 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(()=&gt; load modules);

      【讨论】:

      • 我不认为我喜欢这个静态实例,尤其是在像 prism 这样的基于依赖注入的框架的上下文中。此外,即使使用常规的网络事件,在加载模块时阻塞 ui 线程时,您也不会获得 ui 更新...
      • 你必须在单独的线程上加载模块,然后你可以在 Ui 线程上监听它。我同意,静态事件对于 DI 框架并不是最好的,但是它们会按照他的要求进行。我能够让它工作。
      猜你喜欢
      • 2023-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多