【问题标题】:How to prevent focus steal from window in same application?如何防止在同一应用程序中从窗口窃取焦点?
【发布时间】:2015-11-02 11:53:46
【问题描述】:

使用SetWindowLong()WS_EX_NOACTIVATE 我已将窗口设为不可激活。

  • 如果我将光标放在记事本中并单击不可激活的窗口,则光标在记事本中仍处于活动状态。
  • 如果我将光标放在应用程序内的另一个窗口中并单击不可激活的窗口,则光标将从另一个窗口中删除。

我做了一个小项目来重现这个问题:http://s000.tinyupload.com/index.php?file_id=78888532457762447347

基本上是一个有两个窗口的 WPF 应用程序:

主窗口

// XAML code
<Window x:Class="CS_test.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Background="LightGray" Height="300" Width="400">
    <Grid>
        <TextBox Width="300" Height="200"></TextBox>
    </Grid>
</Window>

// C# code
namespace CS_test
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            new NonActiveWindow().Show();
        }
    }
}

非活动窗口

// XAML code
<Window x:Class="CS_test.NonActiveWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="NonActiveWindow" Height="300" Width="300"
        Loaded="Window_Loaded">
    <Grid>
    </Grid>
</Window>

// C# code
namespace CS_test
{
    public partial class NonActiveWindow : Window
    {
        [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);

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

        public NonActiveWindow()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            WindowInteropHelper windowHelper = new WindowInteropHelper(this);
            SetWindowLong(windowHelper.Handle, GWL_EXSTYLE, GetWindowLong(windowHelper.Handle, GWL_EXSTYLE) | WS_EX_NOACTIVATE);
        }
    }
}

我知道可以通过在单独的线程(使用单独的 Dispatcher)中实例化 NonActiveWindow 来解决此问题,但由于线程问题,我无法使用此方法。

有没有办法防止焦点丢失而不在单独的线程中创建不可激活的窗口?

编辑:

显示问题的视频(回应贾斯汀的回答):

https://www.youtube.com/watch?v=6RNmJc7ya48

以防万一有人想知道为什么拖动时窗口没有更新:Create a window using the WS_EX_NOACTIVATE flag ,but it can't be dragged until I release the mouse

【问题讨论】:

  • 不能解决问题。这是窗口具有相同 UI 线程时的一些特殊行为。
  • SetWindowLongPtr: "某些窗口数据被缓存,因此您使用 SetWindowLongPtr 所做的更改在调用SetWindowPos 函数之前不会生效。"
  • 我尝试在 SetWindowLong() 之后调用 SetWindowPos() - 没有变化。
  • 否定。实现了一种解决方法,我在自己的应用程序中存储窗口句柄并忽略来自窗口的句柄。

标签: c# winapi


【解决方案1】:

ShowActivated 属性对我来说工作正常:

public MainWindow()
{
    InitializeComponent();
    var otherWindow = new NonActiveWindow()
    {
        ShowActivated = false
    };
    otherWindow.Show();
}

我的OtherWindow 只是一个空的 WPF 窗口,没有您的示例所具有的任何 P/Invoke 调用。

请注意,MainWindow 显示得非常轻微 OtherWindow 显示之后,因为此调用在构造函数中。如果你想解决这个问题,那么你应该在构造函数之外调用Show,例如在Loaded 事件中。

【讨论】:

  • 还是不行。捕获了一个应该非常清楚地显示问题的视频:youtube.com/watch?v=6RNmJc7ya48
  • 好的,我想我更能理解您现在的要求 - 我不确定我知道该怎么做。
  • @Woodgnome 该视频现在是私有的。我可以看视频吗?我可能面临同样的问题。
猜你喜欢
  • 2016-04-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-14
  • 2011-11-04
相关资源
最近更新 更多