2017-06-18 89 views
1

我有一個C#應用程序使用多個事件處理程序,它是由各種事件觸發的。舉個例子:考慮多個事件

  1. 全球鼠標鉤子事件
  2. 被過濾(處理程序只能使用特定的按鍵觸發)
  3. 活動窗口改變全局鉤子
  4. 結構發生變化的應用程序掛鉤全球主要掛機事件(這是一個UIAAutomation事件,當它變成活動窗口時,會爲每個應用程序窗口創建不同的結構更改事件/處理程序(例如,如果應用程序是Internet Explorer,然後調低瀏覽器,單擊另一個網站鏈接是在Internet Explorer應用程序實例上更改結構)

所有這些事件(在後臺線程上運行,例如, MTA)具有更新我的應用程序的UI窗口的效果。他們都在按照他們的要求工作。

我的問題是,在某些情況下同時觸發多個事件。因此,例如,它是可行的下列事件都在1秒內觸發(如果我點擊了一個不同的活動窗口中會出現這樣的情景):

  1. 全球活動窗口的變化
  2. 全球鼠標鉤子
  3. 應用程序結構已更改。

在不同的情況下(例如,不同的活動的應用程序)一個事件在另一個的上面優選作爲由一組條件(布爾)統治定義事件。我不想在特定的時間段內參加一個以上的活動。

什麼是最好的編程機制,用於考慮觸發事件並根據一組條件決定採取哪一種行動?當然,這一切都必須在很短的時間內完成(例如一秒或更短)。所觸發的事件都會在這段時間內發生。

我希望這是有道理的,如果沒有請請澄清。順便提一下,我想通過某個定義事件來更新我的應用程序的UI的原因是,根據哪個事件被觸發,我的UI呈現的信息會略有不同(主要是由於不同事件發生時間的細微差異觸發)。順便提及,觸發特定事件所用的時間取決於所採取的行動(例如,單擊不同的活動窗口)。有時一種事件類型比另一種更快,但在不同的情況下,不同的事件類型可能是最快的事件(或觸發的最慢事件)

謝謝以下兩個答案,非常感謝。首先,我將檢查System.Reactive庫,因爲它聽起來是專門爲該任務構建的。

+1

[RX](http://reactivex.io/)應與幫助,但對於一個相當陡峭的學習曲線準備。 –

+1

當事件到達時,啓動計時器(如果未啓動),並將事件信息放入隊列中。當計時器滴答時,從隊列中拉出所有事件,並決定要採取哪一種行動 –

+0

您是否試圖通過一個處理程序來管道所有事件:將事件傳遞給當前處理程序或根據您的要求撤消它規則是什麼? –

回答

0

我一直在使用類似的代碼下面,以防止事件處理衝突:

class Program 
    { 
     enum EVENTS 
     { 
      EVENT1, 
      EVENT2, 
      EVENT3, 
      EVENT4, 

     } 
     static void Main(string[] args) 
     { 

     } 
     static void EventHandler(EVENTS myEvent) 
     { 
       Object thisLock = new Object(); 

       lock (thisLock) 
       { 
        switch (myEvent) 
        { 
         case EVENTS.EVENT1 : 
          break; 
         case EVENTS.EVENT2: 
          break; 
         case EVENTS.EVENT3: 
          break; 
         case EVENTS.EVENT4: 
          break; 
        } 
       } 
     } 

    } 
+0

這是如何防止事件處理中的衝突? – Enigmativity

+0

鎖只允許一個事件通過代碼。因此,如果兩個事件使用相同的資源,則一次只能訪問資源。 – jdweng

+0

好的,所以這隻有在兩個事件幾乎同時在不同的線程上觸發時纔有用。 – Enigmativity

1

微軟的反應框架(的NuGet「System.Reactive」)可以華麗,非常有力地做這種婷。你可以簡單地做一些事情,但是一些查詢 - 特別是那些處理時間的查詢 - 可能會非常複雜。

這裏是你可以做什麼樣:

var event1 = new Subject<int>(); 
var event2 = new Subject<int>(); 

var query = 
    event1.Merge(event2).Buffer(TimeSpan.FromSeconds(1.0)); 

query.Subscribe(xs => Console.WriteLine($"\"{String.Join(", ", xs)}\"")); 

event1.OnNext(42); 
Thread.Sleep(3000); 
event2.OnNext(43); 
Thread.Sleep(500); 
event1.OnNext(44); 

輸出:

 
"42" 
"" 
"" 
"43, 44" 
"" 
"" 

注意,它在同一時間,即使相隔事件觸發500ms的生產"43, 44"

0

下面是我的代碼的簡化版本,其中包含多個全局掛鉤,這些全局掛鉤是通過更改活動窗口和鼠標左鍵單擊來觸發的。如果你點擊不同的活動窗口,鼠標點擊事件和活動窗口事件的改變都將被觸發。如果您可以向我展示使用Reactive命名空間來處理這兩個事件的示例代碼,而這兩個事件是在毫秒內觸發的,我將不勝感激。

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Windows.Forms; 

namespace Testing_multiple_events 
{ 
    public partial class Form1 : Form 
    { 
     int activeWindowCount = 1; 
     int activeMouseClickCount = 1; 
     public Form1() 
     {     
      InitializeComponent(); 
      // set up the global hook event for change of active window 
      GlobalEventHook.Start();    
      GlobalEventHook.WinEventActive += new EventHandler(GlobalEventHook_WinEventActive);       

      // Setup global mouse hook to react to mouse clicks under certain conditions, see event handler 
      MouseHook.Start(); 
      MouseHook.MouseAction += new EventHandler(MouseHook_MouseAction); 
     } 

     private void GlobalEventHook_WinEventActive(object sender, EventArgs e) 
     { 
      richTextBox1.AppendText("Active Window Change Global Hook Triggered: " + activeWindowCount + "\r\n"); 
      activeWindowCount++; 
     }  

     private void MouseHook_MouseAction(object sender, EventArgs e) 
     { 
      richTextBox1.AppendText("Global MouseHook Triggered: " + activeMouseClickCount + "\r\n"); 
      activeMouseClickCount++; 
     } 
    } 
} 


using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Runtime.InteropServices; 

namespace Testing_multiple_events 
{ 
    public static class GlobalEventHook 
    { 
     [DllImport("user32.dll")] 
     internal static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, 
      WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags); 

     [DllImport("user32.dll")] 
     internal static extern bool UnhookWinEvent(IntPtr hWinEventHook); 

     public static event EventHandler WinEventActive = delegate { }; 
     public static event EventHandler WinEventContentScrolled = delegate { }; 

     public delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, 
      int idChild, uint dwEventThread, uint dwmsEventTime); 

     private static WinEventDelegate dele = null; 
     private static IntPtr _hookID = IntPtr.Zero; 



     public static void Start() 
     { 
      dele = new WinEventDelegate(WinEventProc); 
      _hookID = SetWinEventHook(Win32API.EVENT_SYSTEM_FOREGROUND, Win32API.EVENT_OBJECT_CONTENTSCROLLED, IntPtr.Zero, dele, 0, 0, Win32API.WINEVENT_OUTOFCONTEXT); 
     } 

     public static void stop() 
     { 
      UnhookWinEvent(_hookID); 
     } 

     public static void restart() 
     { 

      _hookID = SetWinEventHook(Win32API.EVENT_SYSTEM_FOREGROUND, Win32API.EVENT_OBJECT_CONTENTSCROLLED, IntPtr.Zero, dele, 0, 0, Win32API.WINEVENT_OUTOFCONTEXT); 
     } 

     public static void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime) 
     { 

       if (eventType == Win32API.EVENT_SYSTEM_FOREGROUND) 
       {      
        WinEventActive(null, new EventArgs()); 
       } 
     } 
} 
} 

    using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Runtime.InteropServices; 
using System.Diagnostics; 

namespace Testing_multiple_events 
{ 
    public static class MouseHook 
    { 
     [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     private static extern IntPtr SetWindowsHookEx(int idHook, 
      LowLevelMouseProc lpfn, IntPtr hMod, uint dwThreadId); 

     [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     [return: MarshalAs(UnmanagedType.Bool)] 
     private static extern bool UnhookWindowsHookEx(IntPtr hhk); 

     [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, 
      IntPtr wParam, IntPtr lParam); 

     [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     private static extern IntPtr GetModuleHandle(string lpModuleName); 

     public static event EventHandler MouseAction = delegate { }; 

     private const int WH_MOUSE_LL = 14; 

     private enum MouseMessages 
     { 
      WM_LBUTTONDOWN = 0x0201, 
      WM_LBUTTONUP = 0x0202, 
      WM_MOUSEMOVE = 0x0200, 
      WM_MOUSEWHEEL = 0x020A, 
      WM_RBUTTONDOWN = 0x0204, 
      WM_RBUTTONUP = 0x0205 
     } 

     [StructLayout(LayoutKind.Sequential)] 
     private struct POINT 
     { 
      public int x; 
      public int y; 
     } 

     [StructLayout(LayoutKind.Sequential)] 
     private struct MSLLHOOKSTRUCT 
     { 
      public POINT pt; 
      public uint mouseData; 
      public uint flags; 
      public uint time; 
      public IntPtr dwExtraInfo; 
     } 

     public static void Start() 
     { 
      _hookID = SetHook(_proc); 

     } 
     public static void stop() 
     { 
      UnhookWindowsHookEx(_hookID); 
     } 

     private static LowLevelMouseProc _proc = HookCallback; 
     private static IntPtr _hookID = IntPtr.Zero; 

     private static IntPtr SetHook(LowLevelMouseProc proc) 
     { 
      using (Process curProcess = Process.GetCurrentProcess()) 
      using (ProcessModule curModule = curProcess.MainModule) 
      { 
       IntPtr hook = SetWindowsHookEx(WH_MOUSE_LL, proc, GetModuleHandle("user32"), 0); 
       if (hook == IntPtr.Zero) throw new System.ComponentModel.Win32Exception(); 
       return hook; 
      } 
     } 

     private delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam); 

     private static IntPtr HookCallback(
      int nCode, IntPtr wParam, IntPtr lParam) 
     { 
      if (nCode >= 0 && (MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam || MouseMessages.WM_RBUTTONDOWN == (MouseMessages)wParam || 
       MouseMessages.WM_MOUSEWHEEL == (MouseMessages)wParam)) 
      { 
       MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT)); 
       MouseAction(null, new EventArgs()); 
      } 
      return CallNextHookEx(_hookID, nCode, wParam, lParam); 
     } 

    } 
}