WPF将窗口置于桌面下方

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按钮中的内容
            System.Timers.Timer tmr = new System.Timers.Timer(1000); //1秒一个循环
            tmr.Elapsed += timer_Tick;
            tmr.AutoReset = true;
            tmr.Start();
        } 


改变Button按钮中内容的定时器,

private void timer_Tick(object sender, ElapsedEventArgs e)
{
    this.Dispatcher.InvokeAsync(new Action(() =>
    {
        btnTime.Content = DateTime.Now.ToString("MM-dd HH:mm:ss");
    }));
}

简单心得

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

作者: 丑萌气质狗

出处:https://www.cnblogs.com/choumengqizhigou/p/15702980.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
WPF是一种用于开发Windows应用程序的技术框架。迅雷窗口样式是指在WPF应用程序中使用类似于迅雷软件的窗口样式。 迅雷窗口样式通常包括以下几个特点: 1. 边框和标题栏:迅雷窗口样式通常具有特殊的边框和标题栏设计,可以给用户带来独特的视觉体验。边框和标题栏可以进行自定义,例如可以设置不规则的边框样式,或者给标题栏添加自定义的图标和按钮。 2. 透明效果:迅雷窗口样式通常采用透明效果,可以显示出背后的桌面或其他窗口内容。这样可以增加应用程序的时尚感和科技感。 3. 强调视图:迅雷窗口样式通常会对某些重要的视图元素进行强调,例如下载进度、操作按钮等。这样可以提升用户对这些重要信息的注意力,使其更易于操作。 4. 动画效果:迅雷窗口样式通常会使用各种动画效果来增加交互的流畅性和美观性,例如弹出菜单、窗口缩放等。这样可以提升用户体验,使应用程序更加生动有趣。 开发WPF应用程序时,可以使用XAML语言来定义窗口样式。通过设置窗口的样式属性和使用自定义的控件模板,可以实现类似迅雷窗口样式的效果。同时,WPF还提供了丰富的视觉效果和动画功能,可以进一步增强迅雷窗口样式的效果。 总之,迅雷窗口样式是一种在WPF应用程序中使用类似于迅雷软件的窗口外观和交互效果的设计风格。通过合理运用WPF技术,可以实现这种样式,并提升用户体验和应用程序的吸引力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值