【问题标题】:How to create event subscribers in prism (eventaggregator)如何在 prism (eventaggregator) 中创建事件订阅者
【发布时间】:2015-01-09 12:00:57
【问题描述】:

我的项目中有一个反复出现的模式。

我有发布 eventtaggregator-events 的命令,我有明确订阅事件并处理它们的类。

问题:过去,我从我的应用程序根对象中引用了每个事件处理程序,以确保它们被创建并因此能够“实时”捕获事件。有没有办法让我不必对每个事件处理类都这样做? 所有事件处理程序都命名为 *EventHandler,如果可以使用的话...

我将 Unity 用于 IOC 容器。

感谢您的任何意见,

安德斯,丹麦

    public class PickWishListCommand : BaseCommand, IPickWishListCommand
    {
        private readonly IEventAggregator _eventAggregator;

        public PickWishListCommand(IEventAggregator eventAggregator)
        {
            _eventAggregator = eventAggregator;
        }

        public bool CanExecute(object parameter)
        {
            return true;
        }

        public void Execute(object parameter)
        {
            _eventAggregator
                .GetEvent<PickWishListEvent>()
                .Publish(parameter);
        }
    }

    public class PickWishListEventHandler : IPickWishListEventHandler
    {
        public PickWishListEventHandler(IEventAggregator eventAggregator)
        {
            eventAggregator.GetEvent<PickWishListEvent>().Subscribe(OnEvent);
        }

        private void OnEvent(object obj)
        {
            throw new System.NotImplementedException();
        }
    }

public partial class App
{
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        var container = new UnityContainer();
        container
            .RegisterTypes(
                AllClasses.FromAssembliesInBasePath(),
                WithMappings.FromMatchingInterface,
                WithName.Default,
                WithLifetime.ContainerControlled);

        var executionContext = container.Resolve<IExecutionContext>();
        var configurationApplicationService = container.Resolve<IConfigurationApplicationService>();

        configurationApplicationService.SetupMainWindow();

        //Thread.Sleep(3000);
        var mainWindow = new MainWindow
        {
            DataContext = executionContext.MainWindowViewModel
        };
        mainWindow.Show();
    }
}

编辑:我找到了一种自动实例化的方法——但要保持问题的开放性;可以做得更优雅吗?

     protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);

            var container = new UnityContainer();
            container
                .RegisterTypes(
                    AllClasses.FromAssembliesInBasePath(),
                    WithMappings.FromMatchingInterface,
                    WithName.Default,
                    WithLifetime.ContainerControlled);

            var eventHandlers = new List<object>();

            foreach (var registration in container.Registrations)
            {
                var nameOfRegType = registration.RegisteredType.Name;
                var overrides = new ResolverOverride[] { };
                if (!nameOfRegType.EndsWith("EventHandler") || !nameOfRegType.StartsWith("I")) continue;

                var t = container.Resolve(registration.RegisteredType, overrides);
                eventHandlers.Add(t);
            }
            var executionContext = container.Resolve<IExecutionContext>();
            executionContext.EventHandlers = eventHandlers;

            var configurationApplicationService = executionContext.ConfigurationApplicationService;
            configurationApplicationService.SetupMainWindow();

            var mainWindow = new MainWindow
            {
                DataContext = executionContext.MainWindowViewModel
            };

            mainWindow.Show();
        }

【问题讨论】:

  • 你想达到什么目的?无论如何,如果你想处理这些事件,你需要订阅。您可以使用反射来获取所有EventHandler 类型(类),创建实例并完成订阅工作,但我不建议这样做。很难维护和测试。
  • 嗨 dymanoid,我希望避免在我的应用程序根或子对象中引用每个事件处理程序。通过自动实例化事件处理程序,我可以引入新的事件和事件处理程序并让它们工作,而无需多言。
  • 我不太确定您遇到了什么问题,当我使用EventAggregator 时,我当然不必引用应用程序根目录中的每个事件处理程序。我的各种 VM 的构造函数都使用 Unity IoC 处理 EventAggregator,并订阅他们感兴趣的任何事件(在我的例子中,在它们的构造函数中)。这些虚拟机中的大多数将仅基于正在运行的程序中的用户交互来创建。然后,它们能够响应各种其他 Vms 发布的事件。
  • 使用专用的EventHandlers 课程有什么意义?您为什么不像@Mashton 建议的那样在 ViewModel 中使用您的事件?
  • 这只是个人喜好问题,我猜。我使用事件来处理业务逻辑,它被放置在它自己的程序集中,而来自视图模型的引用更为罕见。我的事件通常代表用户操作。你的方法没有错,我只是更喜欢另一种方式,这给我带来了挑战:)

标签: unity-container prism


【解决方案1】:

只是为了用一些代码澄清我的评论,当我使用 Prism EventAggregator 时,它将采用以下方式:

// A library class holding event classes
public class ThisClassDefinesMyEvents
{
  public class MyImportantEvent : CompositePresentationEvent<string>{};
}

// An example viewmodel, that subscribes to an event
public class SomeRecievingVm
{
  private readonly IEventAggregator _eventAggregator;
  public SomeRecievingVm(IEventAggregator eventAggregator)
  {
    _eventAggregator = eventAggregator;
    _eventAggregator.GetEvent<MyImportantEvent>().Subscribe(MyEventHandlingMethod);
  }

  public void MyEventHandlingMethod(string whatHappened)
  {
    Console.WriteLine(whatHappened);
  }
}

// An example VM that publishes an event, under a couple of different circumstances
public class SomeSendingVm
{
  private readonly IEventAggregator _eventAggregator;
  public SomeSendingVm(IEventAggregator eventAggregator)
  {
    _eventAggregator = eventAggregator;
    _eventAggregator.GetEvent<MyImportantEvent>().Publish("I am alive");
  }

  private void SomeMethodThatHappensSometimes()
  {
    _eventAggregator.GetEvent<MyImportantEvent>().Publish("I've done something");
  }
}

【讨论】:

  • 请注意,视图模型中的事件处理程序最终不会做很多业务工作,这似乎是 OP 的意图。如果处理程序调用实际完成工作的服务也没关系,但如果多个视图模型涉及相同的“业务事物”,即使这样也会变得混乱
猜你喜欢
  • 2021-01-23
  • 1970-01-01
  • 1970-01-01
  • 2011-09-14
  • 2020-03-29
  • 1970-01-01
  • 1970-01-01
  • 2010-12-21
  • 2011-08-14
相关资源
最近更新 更多