如何使用自定义图像和 onclick 函数在 C# Windows 应用程序中发出通知?

gcd*_*dev 9 c# notifications

我的最终目标是在 C#.NET 中创建一个向用户显示通知的 Windows 10 应用程序。该通知应包含标题、描述、至少一张图像,并且单击时应打开一个网页。如果用户没有点击它,它也应该存储在通知管理器中(或者 Windows 中列出通知的任何地方)。这就是目标。

我尝试了很多不同的方法来做到这一点,但无法让其中任何一个正常工作。

我当前的代码使用Microsoft.Toolkit.Uwp.NotificationsNuGet 包,主要取自以下示例: https: //learn.microsoft.com/en-us/windows/uwp/design/shell/tiles-and-notifications/adaptive-interactive-toasts ?tabs =构建器语法

就目前而言,以下代码效果很好:

using System;
using System.Windows;
using Microsoft.Toolkit.Uwp.Notifications;

namespace PushClient
{
    public partial class App : System.Windows.Application
    {
        private void Application_Startup(object sender, StartupEventArgs e)
        {
            new ToastContentBuilder()
            .AddText("My Title")
            .AddText("My Description")
            .Show();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是它产生的通知...

只需标题和描述


第一个问题

第一个问题是我无法添加自定义图像,尽管据说可以通过三种不同的方法添加图像。我首先尝试了这个:

new ToastContentBuilder()
.AddText("My Title")
.AddText("My Description")
.AddAppLogoOverride((new Uri("https://picsum.photos/48?image=883")), ToastGenericAppLogoCrop.Circle)
.Show();
Run Code Online (Sandbox Code Playgroud)

这成功地删除了通知左侧的默认图标,并在底部添加了应用程序的名称(因为这个想法是徽标已被删除,因此必须通过其他方法来识别应用程序)。然而,并没有新的形象取代旧的形象。只是空白。

空的图标区域

我也尝试过这样做:

new ToastContentBuilder()
.AddText("My Title")
.AddText("My Description")
.AddHeroImage(new Uri("https://picsum.photos/364/180?image=1043"))
.Show();
Run Code Online (Sandbox Code Playgroud)

但据我所知,这与第一个版本相比几乎没有任何改变。

与纯文本版本相同

最后我尝试了这个:

new ToastContentBuilder()
.AddText("My Title")
.AddText("My Description")
.AddInlineImage(new Uri("https://picsum.photos/360/202?image=1043"))
.Show();
Run Code Online (Sandbox Code Playgroud)

这似乎在描述下方添加了一些空白,但没有图像。

脚下有空白


第二个问题

另一个问题是我无法弄清楚如何通过此过程添加完整的 onclick 操作。我对需要单击的按钮或通知本身的单击操作非常满意。但无论它如何工作,它最终都需要在用户的默认浏览器中打开指定的 URL。


其他尝试

我还玩过其他发送通知的过程,比如这个ShowBalloonTip过程。这似乎根本没有自定义图像的选项,这正是我想要的。但是,我可以从指定的图像列表中选择一个图像,包括我在这段代码中选择的“警告”图标,并且 onclick 操作很容易添加:

using System;
using System.Threading;
using System.Windows;
using System.Windows.Forms;

namespace PushClient
{
    public partial class App : System.Windows.Application
    {
        private NotifyIcon _notifyIcon = new NotifyIcon();

        private void Application_Startup(object sender, StartupEventArgs e)
        {
            try
            {
                _notifyIcon = new NotifyIcon();
                _notifyIcon.Icon = PushClient.Properties.Resources.accountable2you;
                _notifyIcon.Visible = true;
                _notifyIcon.ContextMenuStrip = new System.Windows.Forms.ContextMenuStrip();

                Thread t = new Thread(() => LaunchBalloonNotification(_notifyIcon, "My Title", "My Description"));
                t.Start();
            }
            catch (System.Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }
        private static void notifyIcon_BalloonTipClicked(object sender, EventArgs e)
        {
            Console.WriteLine("Action clicked");
        }
        private static void LaunchBalloonNotification(NotifyIcon ico, String title, String msg)
        {
            ico.ShowBalloonTip(
                10000,
                title,
                msg,
                ToolTipIcon.Warning
            );
            ico.BalloonTipClicked += new EventHandler(notifyIcon_BalloonTipClicked);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

没有自定义图像

我也尝试过使用ToastNotificationManager,但我得到的结果与我得到的结果相同Microsoft.Toolkit.Uwp.Notifications......除了ToastNotificationManager需要AppID工作,而且我很难弄清楚我应该如何正确地创建这样一个我的小型 Visual Studio 测试应用程序的东西。

不管怎样,如果你能指出正确的方向来帮助我实现我的目标(最好是一个最小的、可重现的例子!),我将不胜感激!

gcd*_*dev 7

在评论中提供的链接 @Fildor 的帮助下,以及对如何处理本地图像的一些创造性思考,我终于有了一个可行的解决方案。这是链接: https://learn.microsoft.com/en-us/windows/uwp/design/shell/tiles-and-notifications/send-local-toast ?tabs=desktop

我最终将我需要的两个图像(这两个图像都将与应用程序一起部署)转换为数据 URI,就像人们可能在 HTML 中使用的那样。然后我把它们保存在本地。Uri然后我在方法中使用 C#对象AddAppLogoOverride。可能有一种更简单的方法,但这是我能想到的最有效的方法。

我的修改和工作(即“工作”,如果您使用上传到 Opinionatedgeek 编码器的真实图像中的真实图像数据)示例代码如下。

using System;
using System.Windows;
using Microsoft.Toolkit.Uwp.Notifications;
using System.IO;

namespace PushClient
{
    public partial class App : System.Windows.Application
    {
        private String imageFilePath = String.Empty;

        private void Application_Startup(object sender, StartupEventArgs e)
        {
            try
            {
                SaveImageFilesToCommonFolder();
                LaunchToastNotification("Hello World!", "This is such a nice world!", "https://presuppositions.org");
            }
            catch (System.Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }

        private void LaunchToastNotification(string title, string description, string url)
        {
            // https://learn.microsoft.com/en-us/windows/uwp/design/shell/tiles-and-notifications/send-local-toast?tabs=desktop
            Uri img = new Uri(imageFilePath);

            // Listen to notification activation
            ToastNotificationManagerCompat.OnActivated += toastArgs =>
            {
                // Obtain the arguments from the notification
                ToastArguments args = ToastArguments.Parse(toastArgs.Argument);
                // /sf/ask/320618441/
                System.Diagnostics.Process.Start(args["url"]);
            };

            new ToastContentBuilder()
                .AddText(title)
                .AddText(description)
                .AddAppLogoOverride(img)
                .AddButton(new ToastButton()
                    .SetContent("View Report")
                    .AddArgument("action", "viewReport")
                    .AddArgument("url", url))
                .Show();
        }

        private string SaveDataUrlToFile(string dataUrl, string savePath)
        {
            // /sf/ask/1939740351/
            var binData = Convert.FromBase64String(dataUrl);
            System.IO.File.WriteAllBytes(savePath, binData);
            return savePath;
        }

        private void SaveImageFilesToCommonFolder()
        {
            // /sf/ask/1939740351/
            // Write images to common app data folder
            var directory = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
            // Uploaded PNG to this location to get the Data URI,
            // which is really much longer than displayed here:
            // https://www.opinionatedgeek.com/codecs/base64encoder
            String imageFileData = "iVBORw0KGgoAAAANUgAAAMAAAADRU5ErkJggg==";
            imageFilePath = Path.Combine(directory, "myimage.png");
            SaveDataUrlToFile(imageFileData, imageFilePath);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)