2012-08-06 67 views
3

我有兩個類,Input和「EventSystem」。 EventSystem是處理「內部應用程序事件」的內部(非系統相關)類。輸入是一個依賴類(系統相關),處理鍵/按鈕事件並將它們映射到關鍵事件和「EventSystem」。我會告訴你我目前是如何傳遞數據的,它在內部看起來很乾淨,但在外面很髒。有誰知道更好的方法 - 或更簡單的方法 - 傳遞自定義值?向事件系統傳遞自定義數據/值

的EventSystem:

// Raisable Events 
public enum EventType { Action, Cancel }; 

// Base for custom arguments 
public class EventArguments 
    { 
     public double time; 

     public EventArguments(double _time) 
     { 
      time = _time; 
     } 
    } 


// Event Delegate (invoked on raise) 
public delegate void Event(EventArguments eventArgs); 

// full class 
static class EventSystem 
{ 
    private static Dictionary<EventType, Event> eventMapping = new Dictionary<EventType, Event>(); 

    public static void HookEvent(EventType eventType, Event _event) 
    { 
     if (eventMapping.ContainsKey(eventType)) 
     { 
      eventMapping[eventType] += _event; 
     } 
     else 
     { 
      eventMapping.Add(eventType, _event); 
     } 
    } 

    public static void RaiseEvent(EventType eventType, EventArguments args) 
    { 
     if (eventMapping.ContainsKey(eventType)) 
     { 
      eventMapping[eventType].Invoke(args); 
     } 
     else 
     { 
      // do nothing 
     } 
    } 
} 

我輸入ARGS只是繼承EventArguments。

// Inherits EventArguments (double time) and adds it's own, "bool pressed" 
class KeyInputArguments : EventArguments 
{ 
    public bool pressed; 

    public KeyInputArguments(double time, bool _pressed) : 
     base(time) 
    { 
     pressed = _pressed; 
    } 
} 

當一個鍵被按下它觸發鍵(輸入)的事件,則它檢查以查看是否鍵被映射到內部事件,提高它。一個單獨的類(Config)處理映射/綁定鍵到事件的所有配置。

// Raise on press 
EventSystem.RaiseEvent(eventType, new KeyInputArguments(time, true)); 
// [...] 
// Raise on release 
EventSystem.RaiseEvent(eventType, new KeyInputArguments(time, false)); 

最後,爲了觸發事件,我們必須註冊的關鍵事件(這是「外部」代碼)

// Hook our "Enter" function into the Action event 
EventSystem.HookEvent(EventType.Action, Enter); 

// [...] 

public void Enter(EventArguments eventArg) 
{ 
    if (((KeyInputArguments)eventArg).pressed == false) 
    { 
     Error.Break(); 
    } 
} 

一切都很好,直到我看到'我的C#和OOP編程知識有限,這是一個難看的結果

我無法更改Enter方法參數,因爲事件委託明確需要EventArgum經濟需求。 (即使KeyInputArguments繼承它?)。我也不明白爲什麼要將eventArg投入到KeyInputArguments。

最後,我也試過這個(雖然我不喜歡那麼多)

KeyInputArguments keyInputArguments = (KeyInputArguments)eventArg; 
      if (keyInputArguments.pressed == false) 

我需要自定義數據的原因是,我打算從多形式的輸入,如遊戲手柄的接收輸入。這意味着我可以將系統相關數據(遊戲手柄設備信息)處理爲獨立參數。這將系統相關數據限制在我的Input類中,同時將我的事件系統作爲獨立的內部使用。 我在做什麼有更好的方法嗎?

+1

你可以看看使用「as」操作符。 http://msdn.microsoft.com/en-us/library/cscsdfbt(v=vs.100).aspx – 2012-08-06 04:52:43

+0

不能直接回答你的問題,但你可以看看棱鏡的事件聚合器,我認爲做你需要什麼http://msdn.microsoft.com/en-us/library/ff921122%28v=pandp.20%29.aspx – 2012-08-06 05:46:43

回答

2

將這個代碼在項目中的某處:

public static class SomeClassName 
{ 
    public static T CastTo<T>(this object source) 
    { 
     return (T)source; 
    } 
} 

這使您可以編寫

if(!eventArg.CastTo<KeyInputArguments>().pressed) 
    Error.Break(); 

我真的很喜歡這一點,因爲它節約了留下來的東西正確的順序。編寫linq時這是特別好的。

在回答你的問題「即使KeyInputArguments繼承它?」。這裏的問題是你已經定義了一個使用基類的通用目的方法,它不知道繼承類。您將需要對方法使用泛型來解決這一問題,例如,在事件類型傳遞作爲一種通用的參數

public static void HookEvent<TEventType>(....) 
+0

我還沒有研究仿製藥呢。我會看看今天晚上我能改善什麼! – 2012-08-06 14:34:30

0

我結束了混合MikeKulls回答「HookEvent」,並從朋友一些建議,並想出了此:

// Event types to raise. 
enum EventType { Action, Cancel }; 

// Base abstract class to use in the generic type field 
abstract class BaseEvent 
{ 
    public double time; 

    protected BaseEvent(double _time) 
    { 
     time = _time; 
    } 
} 

// Event delegate, T is a sub of BaseEvent that contains the data we need to send 
delegate void EventDelegate<T>(T eventClass) where T : BaseEvent; 

// Event class 
static class EventSystem 
{ 
    // EventClass is the storage of all the generic types and their mapping to an event delegate. 
    private static class EventClass<T> where T : BaseEvent 
    { 
     public static Dictionary<EventType, EventDelegate<T>> eventMapping = new Dictionary<EventType, EventDelegate<T>>(); 
    } 

    /// <summary> 
    /// Hooks an event to a delegate for use with EventSystem.RaiseEvent 
    /// </summary> 
    /// <typeparam name="T">Sub-class of BaseEvent that your delegate will be receiving</typeparam> 
    /// <param name="eventType">Type of event to hook to</param> 
    /// <param name="_event">The callback</param> 
    public static void HookEvent<T>(EventType eventType, EventDelegate<T> _event) where T : BaseEvent 
    { 
     if (EventClass<T>.eventMapping.ContainsKey(eventType)) 
     { 
      EventClass<T>.eventMapping[eventType] += _event; 
     } 
     else 
     { 
      EventClass<T>.eventMapping.Add(eventType, _event); 
     } 
    } 

    /// <summary> 
    /// Raises an event and calls any callbacks that have been hooked via HookEvent 
    /// </summary> 
    /// <typeparam name="T">The sub-class of BaseEvent you are sending</typeparam> 
    /// <param name="eventType">Type of event you are raising</param> 
    /// <param name="args">A subclass of BaseEvent containing the information to pass on</param> 
    public static void RaiseEvent<T>(EventType eventType, T args) where T : BaseEvent 
    { 
     if (EventClass<T>.eventMapping.ContainsKey(eventType)) 
     { 
      EventClass<T>.eventMapping[eventType].Invoke(args); 
     } 
     else 
     { 
      // do nothing 
     } 
    } 
} 

我設置輸入象這樣:

class KeyEvent : BaseEvent 
    { 
     public bool pressed; 

     public KeyEvent(double _time, bool _pressed) 
      : base(_time) 
     { 
      pressed = _pressed; 
     } 
    } 
// [...] 
// Key down 
EventSystem.RaiseEvent<KeyEvent>(eventType, new KeyEvent(time, true)); 
// Key up 
EventSystem.RaiseEvent<KeyEvent>(eventType, new KeyEvent(time, false)); 

我安裝該處理程序/委託這樣的:

EventSystem.HookEvent<KeyEvent>(EventType.Action, Enter); 
// [...] 
public void Enter(KeyEvent keyEvent) 
{ 
    if (keyEvent.pressed == false) 
    { 
     Error.Break(); 
    } 
} 
相關問題