【问题标题】:Disable WPF Window Focus禁用 WPF 窗口焦点
【发布时间】:2012-09-17 11:57:57
【问题描述】:

我有一个 WPF 窗口,只有当您通过 Visibility.Hidden 和 Visibility.Visible 按住 Tab 键时才会显示该窗口。但是,按住该键会将焦点从活动应用程序转移到 WPF 窗口。我可以禁用此行为吗?更进一步:是否有可能完全阻止窗口在单击控件时获得焦点,但仍然注册控件的单击动作?

【问题讨论】:

  • @rugk 这是不同的,因为另一个问题是询问如何在不集中注意力的情况下显示,但对于是否允许用户交互却含糊其辞。答案也只解决了不激活的部分,但不清楚是否允许用户交互(顶部选择的答案不允许)。

标签: c# wpf focus


【解决方案1】:

在别处找到答案:

protected override void OnSourceInitialized(EventArgs e)
{
    base.OnSourceInitialized(e);

    //Set the window style to noactivate.
    var helper = new WindowInteropHelper(this);
    SetWindowLong(helper.Handle, GWL_EXSTYLE,
        GetWindowLong(helper.Handle, GWL_EXSTYLE) | WS_EX_NOACTIVATE);
}   

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

[DllImport("user32.dll")]
public static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);

[DllImport("user32.dll")]
public static extern int GetWindowLong(IntPtr hWnd, int nIndex);

【讨论】:

  • 这需要发生在 Loaded 事件中,该事件发生在 Activated 事件之前。如果您在 OnActivated 中执行此操作,则窗口已经激活并且为时已晚......它只会阻止焦点从该点开始。
  • 最好使用 SourceInitialized
  • 最好使用SetWindowLongPtr和GetWindowLongPtr。请参阅 pinvoke.net 网站上的定义。
【解决方案2】:

由于 .NET 3.5 SP1 WPF 表单具有 ShowActivated 属性。设置这个 到false,这样标记的表单不会再窃取任何焦点。

【讨论】:

  • 我已经尝试过了。它只会导致我的程序崩溃。
【解决方案3】:

您可以通过添加自定义 WndProc 并处理 WM_MOUSEACTIVATE 来防止 WPF 窗口在鼠标单击时激活:

protected override void OnSourceInitialized(EventArgs e)
{
    base.OnSourceInitialized(e);
    var source = PresentationSource.FromVisual(this) as HwndSource;
    source.AddHook(WndProc);
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
    if (msg == WM_MOUSEACTIVATE)
    {
        handled = true;
        return new IntPtr(MA_NOACTIVATE);
    }
    else return IntPtr.Zero;
}
private const int WM_MOUSEACTIVATE = 0x0021;
private const int MA_NOACTIVATE = 0x0003;

参考资料:

【讨论】:

  • 我从未收到 WM_MOUSEACTIVATE 消息
  • 哇!我一直在寻找这个问题的解决方案 2 天,它是唯一为我做到的!非常感谢这段精彩的代码让我学习:)
【解决方案4】:

阻止某些顶级窗口在 WPF 中被激活:

我尝试了这里给出的 Win32 解决方案,但它对我不起作用。虽然它似乎确实阻止了窗口“激活”,但Focus 之后仍处于不确定状态,不会恢复到您的应用程序中的另一个合格窗口。相反,以下对我有用:

首先,确保所有非主窗口的Owner 属性设置为主Window。我在子窗口的构造函数中执行此操作,在这种情况下,必须采取一些步骤(此处未讨论)以确保首先加载主 Window。

public MySubWindow()
{
    if ((base.Owner = Application.Current.MainWindow) == null)
        throw new Exception();

    InitializeComponent();
}

设置Owner 属性还应确保子窗口位于主窗口的顶部。对于子窗口,按照指示设置以下属性(XAML 或代码):

ShowActivated="False"
Focusable="False"
ShowInTaskbar="False"
IsEnabled="False"
FocusManager.IsFocusScope="False"

最后,将OnActivated 的处理程序添加到被阻止的窗口。我不调用基本方法,因为它会触发Activated 事件。 (请注意,您不应将激活从 Visual Studio 设计器中切换,因为它会使窗口不可见)。

protected override void OnActivated(EventArgs e)
{
    if (DesignerProperties.GetIsInDesignMode(this))
        return;

    base.Owner.Activate();
}

【讨论】:

    【解决方案5】:

    也许你想要的是 PopupWindow 而不是 Window?它有一个 Focusable 属性,您可以将其设置为 false(我认为默认情况下可能为 false)。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-09-17
    • 2011-03-10
    • 2011-06-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多