【问题标题】:Best way to aggregate event sources and redispatch events聚合事件源和重新调度事件的最佳方式
【发布时间】:2012-06-05 01:21:56
【问题描述】:

我正在尝试找到创建系统的最佳方法,在该系统中可以将事件源添加到管理器类中,然后该管理器类会将其事件重新分配给侦听器。具体来说,我有许多不同的输入源(键盘输入源、鼠标输入源、虚拟键盘输入源等),我希望开发人员能够监听键盘输入源和输入端的 KeyDown 事件管理器本身(从任何活动输入源捕获此事件)。

很容易暴力破解一个解决方案,我最终创建了许多“调度”函数,当它们通过时简单地重新调度事件,但我最终有几十个单行函数,我必须创建新函数每当向输入源界面添加新事件时。

我考虑过使用 lambda,但如果从管理器中删除输入源,我需要一种方法来解除事件挂钩。我可以将 lambda 保存在字典中,由输入源键入,但是许多事件具有不同的 arg 类,并且为此创建多个字典开始变得丑陋。

我想知道我是否遗漏了一些简单的方法来保持清洁并保持我需要写下的额外代码量。

作为参考,这是我正在使用的对象的示例:

public interface IInputSource {}

public interface IKeyboardInputSource : IInputSource
{
    event EventHandler<KeyboardEventArgs> KeyDown;
    event EventHandler<KeyboardEventArgs> KeyUp;
}

public interface IMouseInputSource : IInputSource
{
    event EventHandler<MouseEventArgs> MouseDown;
    event EventHandler<MouseEventArgs> MouseUp;
}

public class InputManager : IKeyboardInputSource, IMouseInputSource
{
    private List<IInputSource> InputSources;

    //Event declarations from IKeyboardInputSource and IMouseInputSource

    public void AddSource(IInputSource source)
    {
        InputSources.Add(source);

        if (source is IKeyboardInputSource)
        {
            var keyboardSource = source as IKeyboardInputSource;
            keyboardSource.KeyDown += SendKeyDown;
            // Listen for other keyboard events...
        }
        if (source is IMouseInputSource)
        {
            // Listen for mouse events...
        }
    }

    public void RemoveSource(IInputSource source)
    {
        if (source is IKeyboardInputSource)
        {
            var keyboardSource = source as IKeyboardInputSource;
            keyboardSource.KeyDown -= SendKeyDown;
            // Remove other keyboard events...
        }
        if (source is IMouseInputSource)
        {
            // Remove mouse events...
        }

        InputSources.Remove(source);
    }

    private void SendKeyDown(object sender, KeyboardEventArgs e)
    {
        if (KeyDown != null) 
            KeyDown(sender, e);
    }

    //Other "send" functions
}

【问题讨论】:

  • 我应该早点提到这一点——但不幸的是,我正在从事的项目不允许我使用任何第三方库。
  • 您可以检查 bbvcommon 库中使用的代码,因为它是开源的,然后您可以复制它并使其适应您的代码。这是源代码的直接链接github.com/bbvcommon/bbv.Common
  • 好点。我去看看!

标签: c# events architecture lambda


【解决方案1】:

你看过Reactive Extensions (Rx) 框架吗?看起来它会满足您的要求,并为您提供丰富的函数式/lambda 类 API 来管理和处理事件。

响应式扩展 (Rx) 是一个库,用于使用可观察序列和 LINQ 样式的查询运算符组合异步和基于事件的程序

【讨论】:

    【解决方案2】:

    可能这样的事情会有所帮助 - 这是一种通用方法,既可以直接订阅事件,也可以通过“接收器”接口

    interface IInputSource<T> where T : EventArgs
    {
        event EventHandler<T> InputEvent;
    }
    interface IInputSink<in T> where T : EventArgs
    {
        void InputMessageHandler(object sender, T eventArgs);
    }
    
    internal class InputManager
    {
        private Dictionary<Type, object> _inputSources;
        private Dictionary<Type, object> _inputSinks;
        private Dictionary<Type, object> _events;
    
        public void AddSource<T>(IInputSource<T> source) where T : EventArgs
        {
            _inputSources[typeof(T)] = _inputSources;      //add source
            _events[typeof(T)] = (EventHandler<T>)Dispatch; //register event for subscribers
    
            source.InputEvent += Dispatch;
            source.InputEvent += Dispatch2;
        }
    
    
        // Dispatch trough direct event subscriptions;
        private void Dispatch<T>(object sender, T e) where T : EventArgs
        {
            var handler = _events[typeof(T)] as EventHandler<T>;
            handler.Invoke(sender, e);
        }
        // Dispatch trough IInputSink subscriptions;
        private void Dispatch2<T>(object sender, T e) where T : EventArgs
        {
            var sink = _inputSinks[typeof(T)] as IInputSink<T>;
            sink.InputMessageHandler(sender, e);
        }
    
        //Subscription:  Client should provide handler into Subscribe()
        //or subscribe with IInputSink<MyEvent> implementation (Subscribe2())
        public void Subscribe<T>(EventHandler<T> handler) where T : EventArgs
        {
            var @event = _events[typeof(T)] as EventHandler<T>;
            _events[typeof(T)] = @event + handler;
        }
    
        public void Subscribe2<T>(IInputSink<T> sink) where T : EventArgs
        {
            _inputSinks[typeof(T)] = sink;
        }
    }
    class XXXX : EventArgs
    {
    
    }
    public class Sink: IInputSink<XXXX>
    {
        #region Implementation of IInputSink<in XXXX>
    
        public void InputMessageHandler(object sender, XXXX eventArgs)
        {
            throw new NotImplementedException();
        }
    
        #endregion
    
        public Sink() 
        {
            var v = new InputManager();
            v.Subscribe<XXXX>(GetInputEvent);
            v.Subscribe2(this);
        }
    
        private void GetInputEvent(object sender, XXXX xxxx)
        {
            throw new NotImplementedException();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2018-10-03
      • 1970-01-01
      • 2021-12-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-27
      • 1970-01-01
      相关资源
      最近更新 更多