.NET MAUI:对于Windows应用程序的任务栏标记通知,有什么变通方法吗?

mutmk8jj  于 2023-03-24  发布在  Windows
关注(0)|答案(1)|浏览(148)

在MAUI for Windows中,Taskbar badge notifications API会静默失败,如microsoft-ui-xaml项目中的this issue所述。当应用程序运行时,它会显示在开始菜单中,但不会显示在任务栏中(但在应用程序关闭后,它会神奇地出现)。
这就是我在谈论徽章通知时所指的:

有没有人知道在Windows上的任务栏中显示徽章通知或更改图标的任何变通方法?关于这个问题的评论建议使用ITaskbarList API,但它似乎是C++库的一部分,我不知道如何在MAUI应用程序中从C#调用它。

blmhpbnm

blmhpbnm1#

我想出了一个解决方案,为任何感兴趣的人创建一个忙碌的红点徽章通知:
基于这两篇文章,我创建了一个类来 Package ITaskbarList API方法:
Windows 7 progress bar in taskbar in C#?
Windows 7 Taskbar SetOverlayIcon from WPF app doesn't work

using System.Drawing;
using System.Runtime.InteropServices;

/// <summary>
/// Sources:
/// https://stackoverflow.com/questions/1295890/windows-7-progress-bar-in-taskbar-in-c
/// https://stackoverflow.com/questions/1024786/windows-7-taskbar-setoverlayicon-from-wpf-app-doesnt-work
/// </summary>
public static class TaskbarManager {

    const int WINDOWS_MAX_PATH = 260;

    public enum TaskbarStates {
        NoProgress = 0,
        Indeterminate = 0x1,
        Normal = 0x2,
        Error = 0x4,
        Paused = 0x8
    }

    public enum TBATF {
        USEMDITHUMBNAIL = 0x1,
        USEMDILIVEPREVIEW = 0x2
    }

    public enum THB : uint {
        BITMAP = 0x1,
        ICON = 0x2,
        TOOLTIP = 0x4,
        FLAGS = 0x8
    }

    public enum THBF : uint {
        ENABLED = 0,
        DISABLED = 0x1,
        DISMISSONCLICK = 0x2,
        NOBACKGROUND = 0x4,
        HIDDEN = 0x8
    }

    [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Auto)]
    public struct THUMBBUTTON {
        public THB dwMask;
        public uint iId;
        public uint iBitmap;
        public IntPtr hIcon;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = WINDOWS_MAX_PATH)]
        public string szTip;
        public THBF dwFlags;
    }

    [ComImport()]
    [Guid("ea1afb91-9e28-4b86-90e9-9e9f8a5eefaf")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    private interface ITaskbarList3 {
        // ITaskbarList
        [PreserveSig]
        void HrInit();
        [PreserveSig]
        void AddTab(IntPtr hwnd);
        [PreserveSig]
        void DeleteTab(IntPtr hwnd);
        [PreserveSig]
        void ActivateTab(IntPtr hwnd);
        [PreserveSig]
        void SetActiveAlt(IntPtr hwnd);

        // ITaskbarList2
        [PreserveSig]
        void MarkFullscreenWindow(IntPtr hwnd, [MarshalAs(UnmanagedType.Bool)] bool fFullscreen);

        // ITaskbarList3
        [PreserveSig]
        void SetProgressValue(IntPtr hwnd, UInt64 ullCompleted, UInt64 ullTotal);
        [PreserveSig]
        void SetProgressState(IntPtr hwnd, TaskbarStates state);
        void RegisterTab(IntPtr hwndTab, IntPtr hwndMDI);
        void UnregisterTab(IntPtr hwndTab);
        void SetTabOrder(IntPtr hwndTab, IntPtr hwndInsertBefore);
        void SetTabActive(IntPtr hwndTab, IntPtr hwndMDI, TBATF tbatFlags);

        void ThumbBarAddButtons(
            IntPtr hwnd,
            uint cButtons,
            [MarshalAs(UnmanagedType.LPArray)] THUMBBUTTON[] pButtons);

        void ThumbBarUpdateButtons(
            IntPtr hwnd,
            uint cButtons,
            [MarshalAs(UnmanagedType.LPArray)] THUMBBUTTON[] pButtons);

        void ThumbBarSetImageList(IntPtr hwnd, IntPtr himl);

        void SetOverlayIcon(
            IntPtr hwnd,
            IntPtr hIcon,
            [MarshalAs(UnmanagedType.LPWStr)] string pszDescription);

        void SetThumbnailTooltip(
            IntPtr hwnd,
            [MarshalAs(UnmanagedType.LPWStr)] string pszTip);

        void SetThumbnailClip(
            IntPtr hwnd,
            [MarshalAs(UnmanagedType.LPStruct)] Rectangle prcClip);
    }

    [ComImport()]
    [Guid("56fdf344-fd6d-11d0-958a-006097c9a090")]
    [ClassInterface(ClassInterfaceType.None)]
    private class TaskbarInstance {
    }

    private static ITaskbarList3 taskbarInstance = (ITaskbarList3)new TaskbarInstance();
    private static bool taskbarSupported = Environment.OSVersion.Version >= new Version(6, 1);

    public static void SetProgressState(IntPtr windowHandle, TaskbarStates taskbarState) {
        if (taskbarSupported) taskbarInstance.SetProgressState(windowHandle, taskbarState);
    }

    public static void SetProgressValue(IntPtr windowHandle, double progressValue, double progressMax) {
        if (taskbarSupported) taskbarInstance.SetProgressValue(windowHandle, (ulong)progressValue, (ulong)progressMax);
    }

    public static void SetIcon(IntPtr windowHandle, IntPtr iconHandle, string description) {
        if (taskbarSupported) taskbarInstance.SetOverlayIcon(windowHandle, iconHandle, description);
    }
}

然后我创建了一个24 x24的png图标,中间有一个大红点,我将它作为嵌入式资源导入到Platforms/Windows/Resources中。

现在剩下要解决的就是得到所有这些指针。

IntPtr GetWindowPtr() => ((MauiWinUIWindow)App.Current.Windows[0].Handler.PlatformView).WindowHandle;

var assembly = Assembly.GetExecutingAssembly();

using (var stream = assembly.GetManifestResourceStream($"{assembly.GetName().Name}.Platforms.Windows.Resources.busy-icon.png")) {
   var bitmap = new Bitmap(stream);
   var iconPtr = bitmap.GetHicon();

   TaskbarManager.SetIcon(GetWindowPtr(), iconPtr, "busy");
}

要清除它,您可以将其设置为IntPtr.Zero:

TaskbarManager.SetIcon(GetWindowPtr(), IntPtr.Zero, null);

请注意,您还应该做清理工作,并调用DestoryIcon,如文档here所示。

相关问题