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

先来看一下效果:

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

窗口介绍

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

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

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

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

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

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

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

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

原理操作

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

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

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

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

具体操作

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

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

<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按钮中内容的定时器,这里就不贴了,随意发挥自己的想象吧!

简单心得

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

又水一篇!

哈哈!

WPF将窗口置于桌面下方(可用于动态桌面)的更多相关文章

  1. WPF 同一窗口内的多线程/多进程 UI(使用 SetParent 嵌入另一个窗口)

    原文 WPF 同一窗口内的多线程/多进程 UI(使用 SetParent 嵌入另一个窗口) WPF 的 UI 逻辑只在同一个线程中,这是学习 WPF 开发中大家几乎都会学习到的经验.如果希望做不同线程 ...

  2. 2000条你应知的WPF小姿势 基础篇<74-77 WPF 多窗口Tips>

    在正文开始之前需要介绍一个人:Sean Sexton. 来自明尼苏达双城的软件工程师.最为出色的是他维护了两个博客:2,000ThingsYou Should Know About C# 和 2,00 ...

  3. WPF自定义窗口基类

    WPF自定义窗口基类时,窗口基类只定义.cs文件,xaml文件不定义.继承自定义窗口的类xaml文件的根节点就不再是<Window>,而是自定义窗口类名(若自定义窗口与继承者不在同一个命名 ...

  4. wpf中子窗口的几个问题

    今天研究了一下wpf中的窗口,写这篇文章来总结一下今天的收获.(转载请注明出处~) 总所周知,窗口是windows系统中十分重要的一个元素(从名字上就能体现出来),而一个应用程序总是包含很多窗口(主窗 ...

  5. WPF自学入门(九)WPF自定义窗口基类

    今天简单记录一个知识点:WPF自定义窗口基类,常用winform的人知道,winform的窗体继承是很好用的,写一个基础窗体,直接在后台代码改写继承窗体名.但如果是WPF要继承窗体,我个人感觉没有理解 ...

  6. VC.【转】窗口置于前台并激活的方法

    1.VC 窗口置于前台并激活的方法 - CSDN博客.html https://blog.csdn.net/oXunFeng/article/details/52681279 2.(http://ww ...

  7. wpf 自定义窗口,最大化时覆盖任务栏解决方案

    原文:wpf 自定义窗口,最大化时覆盖任务栏解决方案 相信很多人使用wpf时会选择自定义美观的窗口,因此会设置WindowStyle="None" 取消自带的标题栏.但这样使用 W ...

  8. WPF自定义窗口最大化显示任务栏

    原文:WPF自定义窗口最大化显示任务栏 当我们要自定义WPF窗口样式时,通常是采用设计窗口的属性 WindowStyle="None" ,然后为窗口自定义放大,缩小,关闭按钮的样式 ...

  9. C# 编写一个小巧快速的 Windows 动态桌面软件

    开源自己前段时间使用 C# 编写的 Windows 动态桌面软件,在接下来的博客我将描写一些技术细节和遇到的一些坑.这个软件可以把视频设置成桌面背景播放,不仅如此而且还可以把网页或一个网页文件设置成桌 ...

随机推荐

  1. 让Qt给你报时,为你读诗词 之 Qt5 TTS

    对,Qt没有食言,9月底如期发布了6.2 LTS.嗯,昨天是9月30日,是月底没错,准时没毛病.博客地址如下 https://www.qt.io/blog/qt-6.2-lts-release 对于老 ...

  2. Feed系统设计分析(类似微博的用户动态分享问题)

    Feed系统 最近在研究一个个人动态分享平台,对动态的推送方式有些疑惑,于是研究到了以下结果. 简介 在信息学里面,Feed其实是一个信息单元,比如一条朋友圈状态.一条微博.一条资讯或一条短视频等,所 ...

  3. awk多文件处理时的分隔符?

    目录 问题来源 解决方法 问题来源 我有两个文件,一个是plink过滤后得到的.fam文件(空格分隔):另一个是样本对应关系文件(tab分隔). 文件1: 文件2: 两个文件匹配,awk常规操作.这里 ...

  4. SUNTANS 及 FVCOM 对流扩散方程求解简介[TBC]

    最近接到一个任务,就是解决FVCOM中对流扩散计算不守衡问题.导师认为是其求解时候水平和垂向计算分开求解所导致的,目前我也没搞清到底有什么问题,反正就是让把SUNTANS的对流扩散计算挪到FVCOM中 ...

  5. Go 命令类型和未命名类型

    Go 命令类型和未命名类型 例子 package main import "fmt" // 使用type声明的是命令类型 // type new_type old_type typ ...

  6. python11文件读写模块

    将文件的打开和关闭,交给上下文管理工具with去实现. def read_file(): """ 读取文件 :return: """ fil ...

  7. 中兴交换机基础配置(备份、dhcp中继、monitor)

    1. 备份配置 格式: copy tftp/sftp/ftp [vrf mng] root: 本地文件 远端文件 1. 通过tftp进行备份,vrf mng表示指定使用管理口链路连接 copy tft ...

  8. 深度探讨 PHP 之性能

    1.缘起 关于PHP,很多人的直观感觉是PHP是一种灵活的脚本语言,库类丰富,使用简单,安全,非常适合WEB开发,但性能低下.PHP的性能是否真的就 如同大家的感觉一样的差呢?本文就是围绕这么一个话题 ...

  9. 在前端页面中使用Markdown并且优化a标签

    近期在自己的项目中加入了对 Markdown 语法 的支持,主要用到的是markedjs这个项目.该项目托管在github上,地址为:https://github.com/markedjs/marke ...

  10. 禁止点击、禁止button触发【c#】

    bts.Attributes["onclick"] = "return false; ";