C# 当WPF应用程序';s控制聚焦
我正试图使用C# 当WPF应用程序';s控制聚焦,c#,wpf,setwindowshookex,C#,Wpf,Setwindowshookex,我正试图使用SetWindowsHookEx将标题跟踪添加到我的时间跟踪器窗口中,但它只能部分工作。以下是我用来向订阅者提供共同响应事件的代码: public class Hooks { #region DllImport delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread,
SetWindowsHookEx
将标题跟踪添加到我的时间跟踪器窗口中,但它只能部分工作。以下是我用来向订阅者提供共同响应事件的代码:
public class Hooks
{
#region DllImport
delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
[DllImport("user32.dll")]
static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags);
private const uint WINEVENT_SKIPOWNPROCESS = 2;
private const uint WINEVENT_SKIPOWNTHREAD = 1;
private const uint WINEVENT_OUTOFCONTEXT = 0;
private const uint EVENT_SYSTEM_FOREGROUND = 3;
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
#endregion DllImport
public static event EventHandler<EventArgs<string>> WindowActivated;
public void Bind()
{
var listener = new WinEventDelegate(EventCallback);
var result = SetWinEventHook(EVENT_SYSTEM_FOREGROUND,
EVENT_SYSTEM_FOREGROUND,
IntPtr.Zero,
listener,
0,
0,
(WINEVENT_OUTOFCONTEXT));
}
private static void EventCallback(IntPtr hWinEventHook, uint eventType, IntPtr hwnd,
int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
System.Diagnostics.Debug.Write("EventCallback enter!");
if (eventType == EVENT_SYSTEM_FOREGROUND)
{
var buffer = new StringBuilder(300);
var handle = GetForegroundWindow();
System.Diagnostics.Debug.Write(string.Format("EventCallback GetWindowText: {0}, '{1}'",
GetWindowText(handle, buffer, 300),
buffer));
if (GetWindowText(handle, buffer, 300) > 0 && WindowActivated != null)
{
System.Diagnostics.Debug.Write(string.Format(
"Calling handlers for WindowActivated with buffer='{0}'",
buffer));
WindowActivated(handle, new EventArgs<string>(buffer.ToString()));
}
}
System.Diagnostics.Debug.Write("EventCallback leave!");
}
}
公共类钩子
{
#德林波特地区
委托void WinEventDelegate(IntPtr hWinEventHook、uint eventType、IntPtr hwnd、int idObject、int idChild、uint dwEventThread、uint dwmsEventTime);
[DllImport(“user32.dll”)]
静态外部IntPtr SetWinEventHook(uint-eventMin、uint-eventMax、IntPtr-hmodWinEventProc、WinEventDelegate-lpfnWinEventProc、uint-idProcess、uint-idThread、uint-dwFlags);
私家侦探WINEVENT_SKIPOWNPROCESS=2;
私家侦探WINEVENT_SKIPOWNTHREAD=1;
私家侦探WINEVENT_OUTOFCONTEXT=0;
私人建筑事件系统前景=3;
[DllImport(“user32.dll”)]
静态外部IntPtr GetForegroundWindow();
[DllImport(“user32.dll”)]
静态外部int GetWindowText(IntPtr hWnd、StringBuilder文本、int计数);
#端域DllImport
已激活公共静态事件事件处理程序窗口;
公共无效绑定()
{
var listener=newwineventdelegate(EventCallback);
var结果=SetWinEventHook(事件、系统、前景、,
事件\系统\前台,
IntPtr.Zero,
听众,
0,
0,
(WINEVENT_out of context));
}
私有静态void EventCallback(IntPtr hwinethook、uint eventType、IntPtr hwnd、,
int idObject、int idChild、uint dwEventThread、uint dwmsEventTime)
{
System.Diagnostics.Debug.Write(“EventCallback回车!”);
if(eventType==事件\系统\前台)
{
var buffer=新的StringBuilder(300);
var handle=GetForegroundWindow();
System.Diagnostics.Debug.Write(string.Format(“EventCallback GetWindowText:{0},{1}”),
GetWindowText(句柄、缓冲区、300),
缓冲区);
if(GetWindowText(句柄,缓冲区,300)>0&&WindowActivated!=null)
{
System.Diagnostics.Debug.Write(string.Format(
“使用缓冲区={0}”调用WindowActivated的处理程序,
缓冲区);
WindowActivated(句柄,新事件参数(buffer.ToString());
}
}
System.Diagnostics.Debug.Write(“EventCallback leave!”);
}
}
我有一个带有单个Textbox
的主ui WPF应用程序,我将钩子事件绑定到文本框内容。当我运行它时,它看起来工作正常,直到它自己聚焦。也就是说,如果我点击WPF窗口的texbox,钩子将停止工作约30-40秒。在这之后,事件捕获就可以工作了,但是再次工作——直到主WPF窗口变为活动状态
你知道它是什么以及如何修复吗?我使用标准Visual Studio模板(VS2012;.NET 4.5)创建了一个新的WPF应用程序。然后,我替换了XAML和代码,如下所示: main window.xaml
<Window x:Class="stackoverflowtest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow">
<Grid>
<StackPanel VerticalAlignment="Top" Margin="15">
<TextBox x:Name="_tb" />
<Button Content="Does Nothing" HorizontalAlignment="Left" Margin="0,15" />
</StackPanel>
</Grid>
</Window>
对我来说,这很好用。我可以在不同的应用程序之间切换,它们的窗口标题反映在WPF应用程序的文本框中。即使文本框已聚焦,也没有延迟。我添加了一个DoNothing按钮
控件,以证明无论texbox还是按钮是聚焦的,它都不会改变行为
我只能假设您遇到的问题与您在事件处理程序中执行的操作有关,或者与某种线程问题有关。原因可能是委托被垃圾收集,因为它被分配到局部变量中。这就是为什么它在30-40秒后停止工作。您需要跟踪自己的WPF应用程序吗?如果不是,你就不能将
WINEVENT\u SKIPOWNPROCESS
传递给SetWinEventHook
调用,或者将回调函数接收到的hwnd
与你自己的窗口句柄进行比较,从而过滤掉它。@Steven Rands我用你指定的标志对它进行了测试。它没有改变。你是如何设置标志的?您需要这样传递它们:WINEVENT\u out of context\124winevent\u SKIPOWNPROCESS
。我在这里用一个测试WPF应用程序尝试过,当应用程序本身成为前台窗口时,它肯定会阻止调用EventCallback
方法。刚才又测试了一次。编译应用程序,运行它,在切换到文本框时检查VS title是否显示在文本框中。在点击应用程序窗口之后,如果切换到另一个窗口(FAR、VS、记事本等),文本框未刷新事件。这就是问题所在。是的,你的样品有效。它看起来像是UI和core的不同程序集引起的问题。钩子类放置在核心组件中。这就是问题所在。
using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows;
using System.Windows.Controls;
namespace stackoverflowtest
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
_hooks = new Hooks(_tb);
_hooks.Bind();
}
readonly Hooks _hooks;
}
public class Hooks
{
public Hooks(TextBox textbox)
{
_listener = EventCallback;
_textbox = textbox;
}
readonly WinEventDelegate _listener;
readonly TextBox _textbox;
IntPtr _result;
public void Bind()
{
_result = SetWinEventHook(
EVENT_SYSTEM_FOREGROUND,
EVENT_SYSTEM_FOREGROUND,
IntPtr.Zero,
_listener,
0,
0,
WINEVENT_OUTOFCONTEXT
);
}
void EventCallback(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild,
uint dwEventThread, uint dwmsEventTime)
{
var windowTitle = new StringBuilder(300);
GetWindowText(hwnd, windowTitle, 300);
_textbox.Text = windowTitle.ToString();
}
#region P/Invoke
const uint WINEVENT_OUTOFCONTEXT = 0;
const uint EVENT_SYSTEM_FOREGROUND = 3;
[DllImport("user32.dll")]
static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc,
WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags);
[DllImport("user32.dll")]
static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject,
int idChild, uint dwEventThread, uint dwmsEventTime);
#endregion
}
}