0

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

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

我考虑过使用 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
}
4

2 回答 2

1

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

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

于 2012-05-30T19:01:54.190 回答
0

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

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();
    }
}
于 2012-05-31T10:55:15.633 回答