C# 考虑多个事件
我有一个C#应用程序,它使用由各种事件触发的多个事件处理程序。例如:C# 考虑多个事件,c#,C#,我有一个C#应用程序,它使用由各种事件触发的多个事件处理程序。例如: 全局鼠标钩子事件 已筛选的全局键挂钩事件(处理程序仅在某些按键时触发) 活动窗口更改全局挂钩 结构更改的应用程序挂钩(这是一个UIA自动事件,当每个应用程序窗口成为活动窗口时,会为其创建不同的结构更改事件/处理程序(例如,如果应用程序是Internet Explorer,则向下翻页浏览器、单击另一个网站链接就是Internet Explorer应用程序实例上结构更改的示例) 所有这些事件(在后台线程上运行,例如MTA)都具有更
非常感谢您提供以下两个答案。我将首先查看System.Responsive库,因为它听起来是专为任务而构建的。我一直在使用下面这样的代码来防止事件处理中的冲突:
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;
}
}
}
}
微软的反应式框架(NuGet“System.Responsive”)可以非常出色、非常强大地完成这类任务。你可以非常简单地完成一些事情,但有些查询——特别是那些处理时间的查询——可能相当复杂 以下是您可能会做的示例:
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);
var event1=新主题();
var event2=新主题();
变量查询=
event1.Merge(event2.Buffer)(TimeSpan.FromSeconds(1.0));
query.Subscribe(xs=>Console.WriteLine($“\”{String.Join(“,”,xs)}\”);
事件1.OnNext(42);
睡眠(3000);
事件2.OnNext(43);
睡眠(500);
事件1.OnNext(44);
这将产生:
"42"
""
""
"43, 44"
""
""
"42"
""
""
"43, 44"
""
""
请注意,它会生成
“43,44”
即使事件间隔500毫秒,也要同时触发。这里是我的代码的简化版本,有几个全局钩子,通过更改活动窗口和鼠标左键单击触发。如果您左键单击其他活动窗口,则会触发鼠标单击事件和活动窗口更改事件。如果可以演示使用反应式名称空间处理两个事件的示例代码,如果它们在几毫秒内被触发,我将不胜感激
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);
}
}
}
应该对此有所帮助,但要为一个相当陡峭的学习曲线做好准备。当事件到达时,如果没有启动,则启动计时器,并将事件信息放入队列中。当计时器滴答作响时,从队列中提取所有事件,并决定要执行哪个事件。您尝试通过一个处理程序传递所有事件,该处理程序可以通过将事件传递到当前处理程序或根据您的规则将其撤销?您能给我举个例子,通过一个处理程序传递所有事件吗?这对我来说是一个新概念。@Scocia888-向我们展示设置您正在监视的对象和相关事件的代码,以便我们至少可以编译和运行您的代码。如果可能的话,让代码触发事件,这样我们就可以看到实际值。如果你不能做到这一点,那么就创建模拟真实代码的替代类,这样我们给你的任何答案都可以转换回你的实际类。这有意义吗?这如何防止事件处理中的冲突?锁只允许一个事件通过代码。因此,如果两个事件使用同一资源,一次只有一个可以访问该资源。好的,因此这只有在两个事件几乎同时在不同线程上触发时才有帮助。您可以修改代码以允许一个事件暂停另一个事件以提供优先级。我喜欢的是,它将所有关键代码放在一个方法中,以便易于同步ronize事件,而不是将代码分散在may模块上。这听起来不错,但这不是OP想要的。他想管理可以相隔1秒的事件。