使 WPF 窗口免疫以显示桌面(防止隐藏)



我有一个WPF窗口,它应该是一个"桌面小工具"。我的用户正在寻求一种方法来防止它在点击"显示桌面"时消失。

使窗口始终位于

最顶层是有效的,但我的一些用户不希望窗口始终位于顶部。

除了每x秒运行一次计时器来激活窗口之外,是否有适当的方法可以实现这一点?

我最终开发了自己的解决方案。我在互联网上搜索了几个星期,试图找到答案,所以我为这个感到骄傲。

因此,我们要做的是使用 pinvoke 为 EVENT_SYSTEM_FOREGROUND 窗口事件创建一个钩子。每当前台窗口发生更改时,都会触发此事件。

现在我注意到的是,当发出"显示桌面"命令时,WorkerW 窗口类将成为前台。

请注意,此 WorkerW 窗口不是桌面,我确认此 WorkerW 窗口的 hwnd 不是桌面 hwnd。

因此,我们所做的是,每当 WorkerW 窗口成为前台时,我们将"WPF 小工具窗口"设置为最顶层!

每当 WorkerW 窗口以外的窗口成为前台时,我们就会从"WPF 小工具窗口"中删除最顶层。

如果你想更进一步,你可以取消注释掉我检查新前景窗口是否也是"PROGMAN"的部分,即桌面窗口。

但是,如果用户在其他显示器上单击其桌面,这将导致您的窗口变得最顶部。就我而言,我不想要这种行为,但我想你们中的一些人可能会。

确认可在 Windows 10 中工作。应该在旧版本的Windows中工作。

using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows;
namespace YourNamespace
{
    internal static class NativeMethods
    {
        [DllImport("user32.dll")]
        internal static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, ShowDesktop.WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags);
        [DllImport("user32.dll")]
        internal static extern bool UnhookWinEvent(IntPtr hWinEventHook);
        [DllImport("user32.dll")]
        internal static extern int GetClassName(IntPtr hwnd, StringBuilder name, int count);
    }
    public static class ShowDesktop
    {
        private const uint WINEVENT_OUTOFCONTEXT = 0u;
        private const uint EVENT_SYSTEM_FOREGROUND = 3u;
        private const string WORKERW = "WorkerW";
        private const string PROGMAN = "Progman";
        public static void AddHook(Window window)
        {
            if (IsHooked)
            {
                return;
            }
            IsHooked = true;
            _delegate = new WinEventDelegate(WinEventHook);
            _hookIntPtr = NativeMethods.SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, _delegate, 0, 0, WINEVENT_OUTOFCONTEXT);
            _window = window;
        }
        public static void RemoveHook()
        {
            if (!IsHooked)
            {
                return;
            }
            IsHooked = false;
            NativeMethods.UnhookWinEvent(_hookIntPtr.Value);
            _delegate = null;
            _hookIntPtr = null;
            _window = null;
        }
        private static string GetWindowClass(IntPtr hwnd)
        {
            StringBuilder _sb = new StringBuilder(32);
            NativeMethods.GetClassName(hwnd, _sb, _sb.Capacity);
            return _sb.ToString();
        }
        internal delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
        private static void WinEventHook(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
        {
            if (eventType == EVENT_SYSTEM_FOREGROUND)
            {
                string _class = GetWindowClass(hwnd);
                if (string.Equals(_class, WORKERW, StringComparison.Ordinal) /*|| string.Equals(_class, PROGMAN, StringComparison.Ordinal)*/ )
                {
                    _window.Topmost = true;
                }
                else
                {
                    _window.Topmost = false;
                }
            }
        }
        public static bool IsHooked { get; private set; } = false;
        private static IntPtr? _hookIntPtr { get; set; }
        private static WinEventDelegate _delegate { get; set; }
        private static Window _window { get; set; }
    }
}

您可以使用窗口的"StateChanged"事件。当"窗口状态"属性更改时,它将触发。可以使用此事件并在状态更改为最小化时最大化窗口。

更新

试试这个代码:

private async void Window_StateChanged_1(object sender, EventArgs e)
    {
        await MaximizeWindow(this);
    }
    public Task MaximizeWindow(Window window)
    {
        return Task.Factory.StartNew(() =>
        {
            this.Dispatcher.Invoke((Action)(() =>
            {
                Thread.Sleep(100);
                window.WindowState = System.Windows.WindowState.Maximized;
            }));
        });
    }

最新更新