8

WPF将窗口置于桌面下方(可用于动态桌面)

 3 years ago
source link: https://www.cnblogs.com/choumengqizhigou/p/15702980.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

WPF将窗口置于桌面下方(可用于动态桌面)

先来看一下效果:

动画

界面元素很简单,就一个Button按钮,然后写个定时器,定时更新Button按钮中的内容为当前时间,下面来介绍下原理,和界面组成。

窗口介绍#

Windows操作系统所有的地方都是窗口,可能这也是系统名字的由来吧,包括你看到的文件夹,桌面,右键菜单,这些都是由界面组成的, 这么多窗口需要有一个合理的显示,就需要用到我们的层级关系,比如两个窗体谁显示在前,谁显示在后。

VS给我们提供了一个查找和查看窗口信息的工具,叫做Spy++,在工具里面:

image-20211217151458112

打开之后了,这里给我们展示了当前系统所有的窗口信息,你也可以点击红色框中的查找工具,来查看你想知道的窗口信息:

image-20211217151754602

来演示一下如何查找窗口,点击上方红色框中的查找窗口按钮,两个随便选一个,会弹出如下窗口:

image-20211217152008249

然后你点击红色区域中的这个控件拖动到你想获取的信息窗口,就能看到当前窗口的详细信息了,包括窗口的句柄、标题、类。

比如我直接将图标拖到桌面上,可以看到这是他显示桌面的信息:

image-20211217154929038

这里我们关掉这个窗口, 回到Spy++的主界面,拖到最底部:

image-20211217155055733

可以看到, Progman Manager是桌面窗口的父窗口,前面小窗口图标是灰色的表示的是此窗口是隐藏的(子窗口拥有和父窗口一致的显示层级)。

原理操作#

现在,我们只需要把我们的界面,也就是放到 Program Manager下面,然后再适当调整它的显示顺序,就可以了,但是这一块我们不好操作。有一个其他路子就是给窗口发送一个特殊的消息,来让我们有操作的空间。

只需要给 Program Manager窗口发送一个消息0x52C,就可以将Program Manager拆分为多个窗口,分别是Program Manager窗口和两个WorkerW窗口。

下面是已经发送过此消息后的样子:

image-20211217160422668

可以看到Program Manager下面已经什么都没有了,内容全都转移到第一个WokerW窗口下,这时候我们只需要将我们的窗口挂在到Program Manager窗口的下方就能又有和它一样的显示层级了(窗口从下到上依次显示,所以这里Program Manager显示在最底层),不过需要注意的是,在Program Manager和第一个WorkerW窗口之间,还存在另外一个WorkerW窗口,在我的系统中,它默认隐藏了,为了确保效果一致,我们需要手动将它隐藏起来。

具体操作#

窗体的部分很简单,就创建个窗体,带一个按钮,设置一些窗口基本的信息,截个代码:

image-20211217161713144

代码部分也贴一下吧(复制代码注意你的命名空间):

<Window
    x:Class="BehindTheDesktop.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:local="clr-namespace:BehindTheDesktop"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="MainWindow"
    Width="800"
    Height="450"
    AllowsTransparency="True"
    Background="Transparent"
    ResizeMode="NoResize"
    WindowStyle="None"
    mc:Ignorable="d">

    <Button
        x:Name="btnTime"
        Click="Button_Click"
        Content="开始"
        FontSize="300"
        Foreground="WhiteSmoke" />

</Window>

然后呢就是后台的代码的部分,获取窗口信息,查找窗口和向桌面窗口发送消息 0x52C,需要用到一些Win32的API,下面直接列出来。

    //Win32方法
    public static class Win32Func
    {
        [DllImport("user32.dll")]
        public static extern IntPtr FindWindow(string className, string winName);

        [DllImport("user32.dll")]
        public static extern IntPtr SendMessageTimeout(IntPtr hwnd, uint msg, IntPtr wParam, IntPtr lParam, uint fuFlage, uint timeout, IntPtr result);

        //查找窗口的委托 查找逻辑
        public delegate bool EnumWindowsProc(IntPtr hwnd, IntPtr lParam);
        [DllImport("user32.dll")]
        public static extern bool EnumWindows(EnumWindowsProc proc, IntPtr lParam);

        [DllImport("user32.dll")]
        public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string className, string winName);

        [DllImport("user32.dll")]
        public static extern bool ShowWindow(IntPtr hwnd, int nCmdShow);

        [DllImport("user32.dll")]
        public static extern IntPtr SetParent(IntPtr hwnd, IntPtr parentHwnd);
    }

下面的代码就是向窗口发送消息,并且隐藏中间WorkerW窗口的方法:

        /// <summary>
        /// 向桌面发送消息
        /// </summary>
        public void SendMsgToProgman()
        {
            // 桌面窗口句柄,在外部定义,用于后面将我们自己的窗口作为子窗口放入
            programHandle = Win32Func.FindWindow("Progman", null);

            IntPtr result = IntPtr.Zero;
            // 向 Program Manager 窗口发送消息 0x52c 的一个消息,超时设置为2秒
            Win32Func.SendMessageTimeout(programHandle, 0x52c, IntPtr.Zero, IntPtr.Zero, 0, 2, result);

            // 遍历顶级窗口
            Win32Func.EnumWindows((hwnd, lParam) =>
            {
                // 找到第一个 WorkerW 窗口,此窗口中有子窗口 SHELLDLL_DefView,所以先找子窗口
                if (Win32Func.FindWindowEx(hwnd, IntPtr.Zero, "SHELLDLL_DefView", null) != IntPtr.Zero)
                {
                    // 找到当前第一个 WorkerW 窗口的,后一个窗口,及第二个 WorkerW 窗口。
                    IntPtr tempHwnd = Win32Func.FindWindowEx(IntPtr.Zero, hwnd, "WorkerW", null);

                    // 隐藏第二个 WorkerW 窗口
                    Win32Func.ShowWindow(tempHwnd, 0);
                }
                return true;
            }, IntPtr.Zero);
        }

然后在MainWindow的构造函数中调用下就行了:

        public MainWindow()
        {
            InitializeComponent();

            //向桌面发送消息
            SendMsgToProgman();
        }

最后贴一下页面Button的Click方法:

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            // 设置当前窗口为 Program Manager的子窗口
            Win32Func.SetParent(new WindowInteropHelper(this).Handle, programHandle);

            //设置button背景色为透明
            btnTime.Background = new SolidColorBrush(Colors.Transparent);
            //设置当前界面的宽高,因为我是双屏,所以不能设置全屏,就以这种方式来设置界面了
            this.Width = 1920;
            this.Height = 1080;
            this.Left = 0;
            this.Top = 0;

            //启动定时器,更新Button按钮中的内容
        }

关于改变Button按钮中内容的定时器,这里就不贴了,随意发挥自己的想象吧!

简单心得#

既然可以把当前的界面放置到桌面图标的下方, 那么在界面中可以设置一些更加好玩的效果,比如播放一个视频,这就是我们的动态桌面了,要是再有点奇思妙想,弄个科技桌面,或者简单粗暴做个俄罗斯方块,也不是不可以! 自由发挥!

又水一篇!


Recommend

  • 31
    • www.solidot.org 5 years ago
    • Cache

    人类首次被置于假死状态

  • 18

    Xamarin Forms WPF 干掉默认的窗口导航条在创建默认的 Xamarin Forms WPF 应用,将和 UWP 应用的界面不相同,在 WPF 项目会显示顶部蓝色的一条,看起来不好看,那么可以如何干掉他 下图是一个默认的 Xamarin Forms 应用

  • 30

    WPF / Windows Forms 检测窗口在哪个屏幕 2020-06-11 10:39 使用 Windows Forms 自带的 System.Windows.Forms.Screen 类可以从一个窗口句柄获取到对应的屏幕...

  • 15
    • ourai.ws 4 years ago
    • Cache

    将人生置于股掌

    将人生置于股掌「我要成为人生赢家!」 这句充满壮志豪情的话,相信很多人都在嘴上或者心里呐喊过,尤其是在对自己的现实生活不满时。既然想要成为人生赢家,就得知道如何才能实现。我相信那些呐喊了的人都想过并且也去寻找那条成为赢家的路了,但绝大部...

  • 10

    WPF 设置 ShowInTaskbar 对窗口最小化的影响在 WPF 中,如果设置了 ShowInTaskbar 为 False 那么窗口将不会在任务栏显示。此时如果设置窗口最小化,那么窗口将会收起来作为没有任务栏时的显示方法 如下面代码 <...

  • 4

    2021-08-04 14:12 美国SEC主席:应将加密交易平台置于监管制度之下,以保护交易者 据U.Today 8月4日报道,在最近与CNBC的Squawk Box节目的谈话中,美国SEC主席Gary Gensler表示,比特币等其他币种属于投机性资...

  • 8
    • lindexi.gitee.io 3 years ago
    • Cache

    WPF 稳定的全屏化窗口方法

    WPF 稳定的全屏化窗口方法本文来告诉大家在 WPF 中,设置窗口全屏化的一个稳定的设置方法。在设置窗口全屏的时候,经常遇到的问题就是应用程序虽然设置最大化加无边框,但是此方式经常会有任务栏冒出来,或者说窗口没有贴屏幕的边。本文的方法是基于 Win32...

  • 3

    V2EX  ›  浏览器 为啥子窗口水平滚动条在窗口下方,相比如果在上方有什么优势吗?   az22c...

  • 11

    急于制造更多芯片将环境进步置于危险之中-51CTO.COM 急于制造更多芯片将环境进步置于危险之中 作者:Harris编译 2022-08-15 10:09:40 一些预测表明,未来十年芯片行业的规模将翻一...

  • 7
    • www.51cto.com 2 years ago
    • Cache

    将身份置于零信任的中心

    将身份置于零信任的中心 作者:qaseven 2022-10-30 16:30:28 现代企业正受到攻击。这就引出了一个问题,即您的业务何时会被破坏,而不是是否会被破坏。网络安全围绕需要保护免受外部威胁的本地应用程序的日子已经...

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK