如何接收 Windows Toast 通知的激活和解除消息

问题描述 投票:0回答:1

我正在为 Delphi 创建一个库,以便使用

Winapi.UI.Notifications
中的接口更轻松地实现 Windows 11 toast 通知。

我想使用

IToastNotifier
将自定义通知发布到操作中心以显示通知,并能够接收通知被取消或激活(单击)时的事件。值得庆幸的是,
IToastNotification
具有
add_Activated()
add_Dismissed()
add_Failed()
方法来注册这些事件触发时的回调。

在 C# 中,添加它们相当容易,如下所示:

public void ShowToastNotification()
{
    // Construct the toast content with data bound fields
    var content = new ToastContentBuilder()
        .AddText("Notification title")
        .GetToastContent();

    // Generate the toast notification
    var toast = new ToastNotification(content.GetXml());
    toast.Activated += Toast_Activated;

    // Show the toast notification to the user
    ToastNotificationManager.CreateToastNotifier().Show(toast);
}

private void Toast_Activated(ToastNotification sender, object args)
{
    ShowMessageDialog($"Toast activated!");
}

为了在 Delphi 中做同样的事情,我编写了以下代码片段:

unit Unit1;
interface

uses
  Winapi.Windows, Vcl.Forms, Winapi.ui.Notifications,
  Winapi.CommonTypes, Winapi.Winrt, Vcl.Dialogs, Winapi.DataRT;

type
  TToastActivatedHandler = class(TInterfacedObject, TypedEventHandler_2__IToastNotification__IInspectable)
    procedure Invoke(sender: IToastNotification; args: IInspectable); safecall;
  end;
  TToastDismissHandler = class(TInterfacedObject, TypedEventHandler_2__IToastNotification__IToastDismissedEventArgs)
    procedure Invoke(sender: IToastNotification; args: IToastDismissedEventArgs); safecall;
  end;

  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  end;

var
  Form1: TForm1;
  ActivateHandle: TToastActivatedHandler;
  DismissHandle: TToastDismissHandler;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var
  HStr: HSTRING;
  S:  string;
  Instance: IInspectable;
  Notifier: IToastNotifier;
begin
  // Notification maanger
  const xml = '<toast activationType="protocol">'+
  ' <visual>'+
  '     <binding template="ToastGeneric">'+
  '         <text>Hello world!</text>'+
  '         <text>This is a test notification.</text>'+
  '         <image src="C:\Windows\System32\@facial-recognition-windows-hello.gif" placement="hero" alt=""/>'+
  '     </binding>'+
  ' </visual>'+
  '</toast>';

  // Create XML
  S := 'Windows.Data.Xml.Dom.XmlDocument';
  WindowsCreateString(PChar(S), Length(S), HStr);
  try
    RoActivateInstance(HStr, Instance);
  finally
    WindowsDeleteString(HStr);
  end;

  // Load XML
  WindowsCreateString(PChar(xml), Length(xml), HStr);
  try
    (Instance as Xml_Dom_IXmlDocumentIO).LoadXml( HStr );
  finally
    WindowsDeleteString(HStr);
  end;

  // Create interfaces
  S := 'App.Test';
  WindowsCreateString(PChar(S), Length(S), HStr);
  try
    Notifier := TToastNotificationManager.CreateToastNotifier(HStr);
  finally
    WindowsDeleteString(HStr);
  end;
  const Notification = TToastNotification.CreateToastNotification( Instance as Xml_Dom_IXmlDocument );

  // Create activator
  ActivateHandle := TToastActivatedHandler.Create;
  DismissHandle := TToastDismissHandler.Create;

  // Prepare
  Notification.add_Activated( ActivateHandle );
  Notification.add_Dismissed( DismissHandle );

  // Show
  Notifier.Show( Notification );
end;

{ TToastActivatedHandler2 }
procedure TToastDismissHandler.Invoke(sender: IToastNotification;
  args: IToastDismissedEventArgs);
begin
  ShowMessage('Toast was dismissed!');
end;

{ TToastActivatedHandler }
procedure TToastActivatedHandler.Invoke(sender: IToastNotification;
  args: IInspectable);
begin
  ShowMessage('Toast was activated');
end;

end.

出现以下通知:

Image of shown notification

但是当我单击通知时,永远不会调用

Invoke()
方法,我不确定为什么。我也尝试了
add_Dismissed()
,但它也出现了同样的问题。

我完全不知道该尝试什么。必须有一种方法可以调用调用方法,但我不确定如何实现这一点。

注意: 运行上面的代码不需要单元文件,我只从其中获取了显示此示例所需的片段。但完整的库可以在 GitHub here 上找到。

delphi notifications windows-runtime
1个回答
0
投票

我已经解决这个问题了!

接口似乎非常依赖其序列化的 GUID,如果没有将正确的 ID 添加到类中,注册将会失败。

由于

TypedEventHandler_2__IToastNotification__IToastDismissedEventArgs
TypedEventHandler_2__IToastNotification__IToastDismissedEventArgs_Delegate_Base
的子接口,我以为它也会继承它的GUID,但似乎事实并非如此。

该修复非常容易应用,只需将

TypedEventHandler_2__IToastNotification__IInspectable_Delegate_Base
TypedEventHandler_2__IToastNotification__IToastDismissedEventArgs_Delegate_Base
接口类分别添加到
TToastActivatedHandler
TToastDismissedHandler
对象即可。

以下是正确的声明:

TToastActivatedHandler = class(TInterfacedObject, TypedEventHandler_2__IToastNotification__IInspectable,
    TypedEventHandler_2__IToastNotification__IInspectable_Delegate_Base)
  public
    procedure Invoke(sender: IToastNotification; args: IInspectable); safecall;
  end;
  TToastDismissedHandler = class(TInterfacedObject, TypedEventHandler_2__IToastNotification__IToastDismissedEventArgs,
    TypedEventHandler_2__IToastNotification__IToastDismissedEventArgs_Delegate_Base)
  public
    procedure Invoke(sender: IToastNotification; args: IToastDismissedEventArgs); safecall;
  end;
© www.soinside.com 2019 - 2024. All rights reserved.