0

イベントソースをマネージャークラスに追加して、リスナーにイベントを再ディスパッチできるシステムを作成するための最良の方法を見つけようとしています。具体的には、さまざまな入力ソース(キーボード入力ソース、マウス入力ソース、仮想キーボード入力ソースなど)があり、開発者がキーボード入力ソースと入力の両方でKeyDownイベントをリッスンできるようにしたいと思います。マネージャー自体(アクティブな入力ソースからこのイベントをキャッチするため)。

多くの「ディスパッチ」関数を作成することになるソリューションを総当たり攻撃するのは簡単です。イベントが発生したときにイベントを再ディスパッチするだけですが、最終的には数十の単一行関数があり、新しい関数を作成する必要があります。イベントが入力ソースインターフェイスに追加されます。

ラムダの使用を検討しましたが、入力ソースがマネージャーから削除された場合にイベントのフックを解除する方法が必要です。ラムダを入力ソースでキー設定された辞書に保持できますが、イベントの多くは異なる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) フレームワークを見たことがありますか? それはあなたが求めているものになるように見え、イベントを管理および処理するための 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 に答える