Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/260.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#WPF如何在鼠标单击控件时不激活主窗口 简明的_C#_Wpf - Fatal编程技术网

C#WPF如何在鼠标单击控件时不激活主窗口 简明的

C#WPF如何在鼠标单击控件时不激活主窗口 简明的,c#,wpf,C#,Wpf,我正在尝试用C#创建一个屏幕键盘应用程序。这个键盘应该像屏幕上的键盘一样,在用户单击按钮时模拟键盘输入。例如,当用户单击“A”按钮时,它应该在输入框中键入A(在另一个应用程序中) 因为我昨晚才有这个想法,现在就开始开发,所以我只做了一个非常简单的测试ui: 它只有一个按钮“A” 问题 问题之一是将窗口设置为鼠标单击时不激活。多亏了我发表的评论,我现在有了以下代码: protected override void OnSourceInitialized(EventArgs e)

我正在尝试用C#创建一个屏幕键盘应用程序。这个键盘应该像屏幕上的键盘一样,在用户单击按钮时模拟键盘输入。例如,当用户单击“A”按钮时,它应该在输入框中键入
A
(在另一个应用程序中)

因为我昨晚才有这个想法,现在就开始开发,所以我只做了一个非常简单的测试ui:

它只有一个按钮“A”

问题 问题之一是将窗口设置为鼠标单击时不激活。多亏了我发表的评论,我现在有了以下代码:

    protected override void OnSourceInitialized(EventArgs e)
    {
        base.OnSourceInitialized(e);
        var winH = (HwndSource) PresentationSource.FromVisual(this);
        // set mouse activate false
        winH.AddHook(WndProc);
    }

    #region WndProc

    private const int WM_MOUSEACTIVATE = 0x0021;
    private const int MA_NOACTIVATE = 0x0003;

    private static IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        if (msg != WM_MOUSEACTIVATE)
            return IntPtr.Zero;

        handled = true;
        return new IntPtr(MA_NOACTIVATE);
    }

    #endregion WndProc
然而,代码并不能很好地工作。仅当单击
主窗口的背景(空白)时,才禁用鼠标激活。如果单击
按钮
,窗口将被激活。因为wpf控件没有HWND,所以我不能
AddHook

此外,尽管单击
main窗口的空白部分
并不会将应用程序带到最前面,但当应用程序在任务栏上突出显示时,似乎仍会激活它

附录-完整代码 MainWindow.xaml:

<Window x:Class="OnScreenKeyPad.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:OnScreenKeyPad"
        mc:Ignorable="d"
        Title="MainWindow" Height="200" Width="200"
        WindowStyle = "None"
        AllowsTransparency="True"            >
    <StackPanel>
        <Button x:Name="KeyA" Content="A" Width="50" Margin="10"/>
    </StackPanel>
</Window>

更新1 我已记录了WindowProc消息列表:

ID   Event

33   WM_MOUSEACTIVATE 
32   WM_SETCURSOR
513  WM_LBUTTONDOWN
NA   OnMouseDownPreviewEvent
70   WM_WINDOWPOSCHANGING
71   WM_WINDOWPOSCHANGED
28   WM_ACTIVATEAPP
134  WM_NCACTIVATE
6    WM_ACTIVATE 
641  WM_IME_SETCONTEXT 
642  WM_IME_NOTIFY
7    WM_SETFOCUS 
8    WM_KILLFOCUS 
641  WM_IME_SETCONTEXT 
641  WM_IME_SETCONTEXT 
7    WM_SETFOCUS 
641  WM_IME_SETCONTEXT 
641  WM_IME_SETCONTEXT 
132  WM_NCHITTEST 
512  WM_NCHITTEST 
132  WM_MOUSEFIRST
514  WM_LBUTTONUP 
533  WM_CAPTURECHANGED
132  WM_NCHITTEST 
NA   ButtonOnClickEvent
现在我大概明白了为什么代码不起作用了
MOUSEACTIVATE
在单击鼠标按钮后立即触发,这是在实际的鼠标按钮事件(ID 513)之前。尽管处理了
MOUSEACTIVATE
并阻止了窗口激活,但鼠标按钮事件将再次激活ID为28的窗口
WM_ACTIVATEAPP
。我已经检查了这些事件的文档,没有一个可以被阻止


也许我可以使用一个标签,并利用它的
PreviewMouseDown
事件。

您需要设置WS\u EX\u NOACTIVATE窗口样式,而不是自己尝试吃掉消息:

private const int WS_EX_NOACTIVATE = 0x08000000;
private const int GWL_EXSTYLE = -20;

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int GetWindowLong(IntPtr hwnd, int index);

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int SetWindowLong(IntPtr hwnd, int index, int newStyle);

protected override void OnSourceInitialized(EventArgs e)
{
  var hWnd = new WindowInteropHelper(this).Handle;
  int style = GetWindowLong(hWnd, GWL_EXSTYLE);
  SetWindowLong(hWnd, GWL_EXSTYLE, style | WS_EX_NOACTIVATE);

  base.OnSourceInitialized(e);
}

以防你不知道,Windows内置了一个屏幕键盘,可以处理所有这些问题,还有许多你还没有遇到的问题(比如口音和非欧洲字符)。如果你的问题特别提到“问题1”,“问题2”,那么你是在邀请一个“过于宽泛”的结尾。每个问题请回答一个问题。@Neil是的,类似但不一样。我不需要这么多的键,但只需要WASD、箭头键、esc等。@spender没有意识到这一点,现在我想可以了:)“第一个问题是将窗口设置为在鼠标单击时不激活。”为什么?如果窗口未激活,应用程序应如何响应按钮单击?
private const int WS_EX_NOACTIVATE = 0x08000000;
private const int GWL_EXSTYLE = -20;

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int GetWindowLong(IntPtr hwnd, int index);

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int SetWindowLong(IntPtr hwnd, int index, int newStyle);

protected override void OnSourceInitialized(EventArgs e)
{
  var hWnd = new WindowInteropHelper(this).Handle;
  int style = GetWindowLong(hWnd, GWL_EXSTYLE);
  SetWindowLong(hWnd, GWL_EXSTYLE, style | WS_EX_NOACTIVATE);

  base.OnSourceInitialized(e);
}