我有一个C#应用程序,它使用由各种事件触发的多个事件处理程序。举个例子:
所有这些事件(在后台线程上运行,例如MTA)都会更新我的应用程序的UI窗口。他们都按照自己的意愿工作。
我的问题是,在某些情况下,会同时触发多个事件。因此,例如,在1秒内触发以下事件是可行的(如果我点击不同的活动窗口,则会出现这种情况):
在不同的情况下(例如,不同的活动应用程序),一个事件优先于另一个事件作为由一组条件(布尔值)规则的定义事件。我不想在特定的时间段内对超过1个事件采取行动。
考虑事件触发和决定的最佳编程机制是什么,通过一系列条件,哪一个可以采取行动?当然,这一切都必须在非常快的时间内完成(例如一秒或更短)。触发的事件都将在这段时间内发生。
我希望这是有道理的,如果没有,请要求澄清。顺便提一下,我想通过某个定义事件更新我的应用程序UI的原因是我的UI呈现的信息将根据触发的事件略有不同(主要是由于不同事件的时间略有不同)触发)。顺便说一下,触发特定事件所花费的时间将根据所采取的动作而变化(例如,点击不同的活动窗口)。有时一种事件类型比另一种更快,但在不同的情况下,不同的事件类型可能是最快的事件(或触发的最慢事件)
非常感谢下面的答案。我将首先检查System.Reactive库,因为它听起来是专门为该任务构建的。
答案 0 :(得分:1)
微软的Reactive Framework(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" "" ""
请注意,即使事件相隔500毫秒,它也会同时产生"43, 44"
。
答案 1 :(得分: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;
}
}
}
}
答案 2 :(得分:0)
这是我的代码的简化版本,其中包含几个全局挂钩,这些挂钩由活动窗口的更改和鼠标左键单击触发。如果您左键单击其他活动窗口,则将触发鼠标单击事件和活动窗口事件的更改。如果您可以向我展示使用Reactive命名空间来处理2个事件的示例代码,当它们在毫秒之内被触发时,我将非常感激。
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);
}
}
}