开发者

使用WPF在Windows实现任务栏缩略图效果

wpF 在 Windows 实现任务栏缩略图

  • 框架支持.NET4 至 .NET8
  • Visual Studio 2022;

在 Windows Vista 系统上,微软首次推出任务栏缩略图预览功能。

Windows 任务栏中,当我们将窗口最小化并将鼠标悬停在图标上,会显示一个窗口预览缩略图。通过 Windows dwM(Desktop Window Manager)[3]提供的 API,我们可以自定义这个缩略图的内容,实现类似音乐播放器当前播放的音乐封面图。

使用WPF在Windows实现任务栏缩略图效果

1. 修改 WindowHelpers.cs

先检查 window 是否为 null 或 imagePath 是否为空。

使用 WindowInteropHelper 获取 window 的句柄 (hwnd);

注册窗口消息钩子,监听 DWM 消息;

window.ShowInTaskbar = true;设置 Window 有任务栏图标,否则无法显示预览缩略图。

public static void SetIconicThumbnail(this Window window, string imagePath)
{
    if (window == null || string.IsNullOrWhiteSpace(imagePath)) return;
    if (!File.Exists(imagePath)) return;
    IntPtr hwnd = new WindowInteropHelper(window).Handle;
    int size = Marshal.SizeOf(typeof(int));
    IntPtr pBool = Marshal.AllocHGlobal(size);
    try
    {
        Marshal.WriteInt32(pBool, 1);
        Win32.DwmSetWindowAttribute(hwnd, DwmWindowAttributes.FORCE_ICONIC_REPRESENTATION, pBool, size);
        Win32.DwmSetWindowAttribute(hwnd, DwmWindowAttributes.HAS_ICONIC_BITMAP, pBool, size);
    }
    finally
    {
        Marshal.FreeHGlobal(pBool);
    }
    var source = HwndSource.FromHwnd(hwnd);
    if (source != null)
    {
        source.AddHook(new HwndSourceHook((IntPtr hwnd2, int msg, IntPtr wParam, IntPtr lParam, refbool handled) =>
        {
            if (msg == WindowsMessageCodes.WM_DWMSENDICONICTHUMBNAIL)
            {
                int width = ((int)((((long)lParam) >> 16) & 0xFFFF));
                int height = ((int)((long)lParam & 0xFFFF));
                try
                {
                    using (var bmp = new Bitmap(imagePath))
                    using (var resized = new Bitmap(bmp, new Size(width, height)))
                    {
                        IntPtr hBitmap = resized.GetHbitmap();
                        Win32.DwmSetIconicThumbnail(hwnd2, hBitmap, (int)DwmWindowAttributes.None);
                        Win32.DeleteObject(hBitmap);
                    }
                }
                catch (Exception ex)
                {
                    thrownew Exception($"DwmSetIconicThumbnail error :{ex.Message}!");
                }

                handled = true;
            }

            return IntPtr.Zero;
        }));
    }
    Win32.DwmInvalidateIconicBitmaps(hwnd);
    window.ShowInTaskbar = true;
}

2. 修改 Win32.cs

DwmSetWindowAttribute 设置打开缩略图显示图片;

DwmSetIconicThumbnail 设置自定义缩略图给任务栏;

DwmInvalidateIconicBitmaps 通知 DWM 当前的缩略图无效,重新请求;

WM_DWMSENDICONICTHUMBNAILDWM 向窗口发送消息,请求新的缩略图;

DeleteObject() 手动释放 GDI ,避免内存泄漏;

[DllImport(Gdi32)]
public static extern bool DeleteObject(IntPtr hObject);

[DllImport(DwmApi)]
public static extern int DwmSetIconicThumbnail(IntPtr hwnd, IntPtr hbmp, phpint dwSITFlags);

[DllImport(DwmApi)]
public static extern int DwmSetWindowAttribute(IntPtr hwnd, DwmWindowAttributes dwAttribute, IntPtr pvAttribute, int cBATtribute);

[DllImport(DwmApi)]
public static extern int DwmInvalidateIconicBitmaps(IntPtr hwnd);

internalclassWindowsMessageCodes
{
    publicconstint WM_DWMSENDICONICTHUMBNAIL = 0x0323;
}

[Flags]
publicenum DwmWindowAttributes : uint
{
    None = 0, 
   www.devze.com DISPLAYFRAME = 1,
    FORCE_ICONIC_REPRESENTATION = 7,
    HAS_ICONIC_BITMAP = 10
}

3. 新增 IconicThumbnailWindowExample.xaml

新增两个按钮切换图片,BtnPrevious_Click 和 BtnNext_Click

Image 控件用于显示任务栏的缩略图。

<wd:Window
    x:Class="WPFDevelopers.Sample.ExampleViews.IconicThumbnailWindowExample"
    XMLns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:converts="clr-namespace:WPFDevelopers.Sample.Converts"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="clr-namespace:WPFDevelopers编程.Sample.ExampleViews"
    xmlns:mc="http://schemas.openxmlformats.org/mar编程kup-compatibility/2006"
    xmlns:model="clr-namespace:WPFDevelopers.Sample.Models"
    xmlns:wd="https://github.com/WPFDevelopersOrg/WPFDevelopers"
    title="使用WPF在Windows实现任务栏缩略图效果"
    Width="600"
    Height="450"
    Icon="pack://application:,,,/WPFDevelopers.Samples;component/WPFDevelopers.ico"
    WindowStartupLocation="CenterScreen"
    mc:Ignorable="d">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="7*" />
            <RowDefinition Height="3*" />
        </Grid.RowDefinitions>
        <Image
            x:Name="ImagePreview"
            Width="200"
            Height="200"
            VerticalAlignment="Bottom" />
        <StackPanel
            Grid.Row="1"
            HorizontalAlignment="Center"
            VerticalAlignment="Center"
            wd:PanelHelper.Spacing="3"
            Orientation="Horizontal">
            <Button
                x:Name="BtnPrevious"
                Width="50"
                Height="50"
                Click="BtnPrevious_Click">
                <wd:PathIcon Width="10" Kind="Previous" />
            </Button>
            <Button
                x:Name="BtnNext"
                Width="50"
                Height="50"
                Click="BtnNext_Click">
                <wd:PathIcon Width="10" Kind="Next" />
            </Button>
        </StackPanel>
    </Grid>
</wd:Window>

4. 新增 IconicThumbnailWindowExample.xaml.cs

BtnNext_ClickcurrentFileIndex = (currentFileIndex + 1) % fileList.Count; 通过代码实现图片循环切换:每次点击按钮时,currentFileIndex 会增加 1,如果超过了 fileList 的最大索引,回到第一个图片。。

BtnPrevious_ClickcurrentFileIndex = (currentFileIndex - 1 + fileList.Count) % fileList.Count; 通过代码实现图片循环切换:每次点击按钮时,currentFileIndex 会减少 1,并且如果当前索引小于 0,回到最后一张图片。

using System;
using System.Collections.Generic;
using System.IO;
using System.Windows;
using System.Windows.Media.Imaging;
using WPFDevelopers.Helpers;

namespaceWPFDevelopers.Sample.ExampleViews
{
    /// <summary>
    /// IconicThumbnailWindowExample.xaml 的交互逻辑
    /// </summary>
    publicpartialclassIconicThumbnailWindowExample
    {
        private List<string> fileList = new List<string>(); 
        privateint currentFileIndex = -1;
        public IconicThumbnailWindowExample()
        {
            InitializeComponent();
            Loaded += IconicThumbnailWindowExample_Loaded;
        }

        private void IconicThumbnailWindowExample_Loaded(object sender, RoutedEventArgs e)
        {
            fileList.Clear();
            currentFileIndex = -1;
            var directorys = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "IconicThumbnail");
            if (!Directory.Exists(directorys)) return;
            string[] files = Directory.GetFiles(directorys);
            fileList.AddRange(files);
        }

        private void BtnPrevious_Click(object sender, RoutedEventArgs e)
        {
            if (fileList.Count == 0) return;
            currentFileIndex = (currentFileIndex + 1) % fileList.Count;
            var img = fileList[currentFileIndex];
            ImagePreview.Source = new BitmapImage(new Uri(img));
            this.SetIconicThumbnail(img);
        }
        private void BtnNext_Click(object sender, RoutedEventArgs e)
        {
            if编程客栈 (fileList.Count == 0) return;
            currentFileIndex = (currentFileIndex - 1 + fileList.Count) % fileList.Count;
            var img = fileList[currentFileIndex];
            ImagePreview.Source = new BitmapImage(new Uri(img));
            this.SetIconicThumbnail(img);
        }
    }
}

效果如下 

使用WPF在Windows实现任务栏缩略图效果

到此这篇关于使用WPF在Windows实现任务栏缩略图效果的文章就介绍到这了,更多相关WPF任务栏缩略图内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新开发

开发排行榜