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

标签 c# notifications

我的最终目标是在 C#.NET 中创建一个 Windows 10 应用程序,向用户显示通知。通知应该有一个标题、描述、至少一张图片,当点击它时,它应该打开一个网页。如果用户没有点击它,它也应该存储在通知管理器中(或 Windows 中列出通知的任何地方)。这就是目标。
我已经尝试了很多不同的方法来做到这一点,但无法让它们中的任何一个正常工作。
我当前的代码使用 Microsoft.Toolkit.Uwp.Notifications NuGet 包,主要取自此示例:
https://docs.microsoft.com/en-us/windows/uwp/design/shell/tiles-and-notifications/adaptive-interactive-toasts?tabs=builder-syntax
就目前而言,以下代码效果很好:

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();
        }
    }
}
这是它产生的通知......
Just title and description

第一个问题
第一个问题是我无法添加自定义图像,即使可以通过三种不同的方法添加图像。我首先尝试了这个:
new ToastContentBuilder()
.AddText("My Title")
.AddText("My Description")
.AddAppLogoOverride((new Uri("https://picsum.photos/48?image=883")), ToastGenericAppLogoCrop.Circle)
.Show();
这成功地删除了通知左侧的默认图标并在底部添加了应用程序的名称(因为这个想法是徽标已被删除,因此必须通过其他方法识别该应用程序)。然而,没有新形象代替旧形象。只是空白。
An empty icon area
我也尝试过这个:
new ToastContentBuilder()
.AddText("My Title")
.AddText("My Description")
.AddHeroImage(new Uri("https://picsum.photos/364/180?image=1043"))
.Show();
但据我所知,这与第一个版本几乎没有任何改变。
Same as the plain text version
最后我试过这个:
new ToastContentBuilder()
.AddText("My Title")
.AddText("My Description")
.AddInlineImage(new Uri("https://picsum.photos/360/202?image=1043"))
.Show();
这似乎在描述下方添加了一些空白,但没有图像。
Blank space at foot

第二个问题
另一个问题是我无法弄清楚如何通过此过程添加完整的 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);
        }
    }
}
No custom image
我也尝试过使用 ToastNotificationManager ,但我得到的结果与我得到的结果相同 Microsoft.Toolkit.Uwp.Notifications ... 除了 ToastNotificationManager需要 AppID工作,我很难弄清楚我应该如何为我的小 Visual Studio 测试应用程序创建这样的东西。
无论如何,如果你能指出我正确的方向来帮助我在这里实现我的目标(最好是 minimal, reproducible example !),我将不胜感激!

最佳答案

在评论中提供的链接@Fildor 的帮助下,以及对如何处理本地镜像的一些创造性思考,我终于有了一个可行的解决方案。链接在这里:
https://docs.microsoft.com/en-us/windows/uwp/design/shell/tiles-and-notifications/send-local-toast?tabs=desktop
我最终将我需要的两个图像(这两个图像都将与应用程序一起部署)转换为数据 URI,就像人们可能在 HTML 中使用的那样。然后我将它们保存在本地。然后我使用 C# Uri AddAppLogoOverride 中的对象方法。可能有一种更简单的方法,但这是我能想到的最好的方法。
我的修订和工作(即 - 如果您使用来自上传到意见极客编码器的真实图像的真实图像数据,则为“工作”)示例代码如下。

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://docs.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);
                // https://stackoverflow.com/questions/4580263/how-to-open-in-default-browser-in-c-sharp
                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)
        {
            // https://stackoverflow.com/questions/27710576/convert-from-a-dataurl-to-an-image-in-c-sharp-and-write-a-file-with-the-bytes
            var binData = Convert.FromBase64String(dataUrl);
            System.IO.File.WriteAllBytes(savePath, binData);
            return savePath;
        }

        private void SaveImageFilesToCommonFolder()
        {
            // https://stackoverflow.com/questions/27710576/convert-from-a-dataurl-to-an-image-in-c-sharp-and-write-a-file-with-the-bytes
            // 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);
        }
    }
}

关于c# - 如何使用自定义图像和 onclick 功能在 C# Windows 应用程序中发出通知?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66694454/

相关文章:

c# - EntityFramework 可以一次发送所有查询吗?

c# - 如何从 XElement 获取字符串形式的 XML 片段?

ios - 我使 Messenger 应用程序基于 APNS,但是如果客户端的通知被触发,则客户端不会收到 APNS 发送的其他客户端的消息

java - 通知不会打开 Activity

android - 模拟器上没有通知声音

c# - 将网站作为包部署到 azure

c# - 有没有办法将 ConcurrentDictionary.TryUpdate 与 lambda 表达式一起使用?

c# - 使用 Fluent NHibernate 检索大型数据集

Android:从通知栏中删除通知

android - 如何在应用程序停止时在 Android 中获取本地通知?