You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Delphi 11.3 VCL:通知进入Windows操作中心后点击不触发OnReceiveLocalNotification

TNotificationCenter点击操作中心通知不触发OnReceiveLocalNotification的问题

结论

这不是预期行为,属于Delphi 11.3中TNotificationCenter在Windows平台的实现疏漏。

原因分析

TNotificationCenter的Windows底层实现仅处理了通知首次弹出时的点击激活事件,未适配Windows操作中心中通知的激活回调逻辑。当通知被归档到操作中心后,Windows通过不同通路触发激活事件,但Delphi的默认封装未监听这部分事件,导致点击操作中心内的通知时无法触发OnReceiveLocalNotification。

解决方案

要实现点击操作中心通知也触发事件,需要手动补充Windows通知激活的处理逻辑。以下是基于原有代码的修改方案,通过直接调用WinRT Toast API实现完整的激活事件捕获:

修改后的完整代码

unit MainUnit;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, System.Notification,
  Winapi.UI.Notifications, System.Win.WinRT;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure ReceiveLocalNotification(Sender: TObject; ANotification: TNotification);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    NotificationCenter1: TNotificationCenter;
    FToastManager: ToastNotificationManager;
    procedure ToastActivated(Sender: TObject; const Args: ToastActivatedEventArgs);
  public
    procedure WndProc(var Message: TMessage); override;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  N: TNotification;
  ToastXml: ToastNotificationXml;
  Toast: ToastNotification;
  ToastNotifier: ToastNotifier;
begin
  // 保留原有TNotificationCenter逻辑,兼容现有代码
  N := NotificationCenter1.CreateNotification;
  try
    N.Title := 'My Title';
    N.AlertBody := 'My alert body';
    NotificationCenter1.PresentNotification(N);
  finally
    N.Free;
  end;

  // 补充WinRT Toast通知,确保操作中心点击能触发事件
  ToastXml := FToastManager.GetTemplateContent(ToastTemplateType.ToastText02);
  try
    // 设置通知标题和内容
    var TextNodes := ToastXml.GetElementsByTagName('text');
    TextNodes.Item(0).AppendChild(ToastXml.CreateTextNode('My Title'));
    TextNodes.Item(1).AppendChild(ToastXml.CreateTextNode('My alert body'));

    Toast := ToastNotification.Create(ToastXml);
    try
      Toast.OnActivated := ToastActivated;
      ToastNotifier := FToastManager.CreateToastNotifier(ExtractFileName(ParamStr(0)));
      try
        ToastNotifier.Show(Toast);
      finally
        ToastNotifier.Free;
      end;
    finally
      Toast.Free;
    end;
  finally
    ToastXml.Free;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  NotificationCenter1 := TNotificationCenter.Create(Self);
  NotificationCenter1.OnReceiveLocalNotification := ReceiveLocalNotification;

  // 初始化WinRT Toast管理器
  FToastManager := ToastNotificationManager.Create;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FToastManager.Free;
end;

procedure TForm1.ReceiveLocalNotification(Sender: TObject; ANotification: TNotification);
begin
  ShowMessage('I received the notification clicked event');
end;

procedure TForm1.ToastActivated(Sender: TObject; const Args: ToastActivatedEventArgs);
begin
  // 统一调用原有处理逻辑
  ReceiveLocalNotification(Self, nil);
end;

procedure TForm1.WndProc(var Message: TMessage);
begin
  inherited;
  // 处理Windows通知激活的消息传递
  if Message.Msg = WM_COPYDATA then
  begin
    var CopyData := PCopyDataStruct(Message.LParam);
    if CopyData^.dwData = DWORD('TOAS') then // 匹配Toast激活的标识
    begin
      ToastActivated(Self, nil);
      Message.Result := 1;
    end;
  end;
end;

end.

方案说明

  1. 引入WinRT的ToastNotificationManager,直接创建Toast通知并注册OnActivated事件,该事件会捕获所有场景(包括操作中心)的点击操作。
  2. 重写WndProc处理WM_COPYDATA消息,确保Windows传递的通知激活信号能被应用接收并触发处理逻辑。
  3. 将原有ReceiveLocalNotification作为统一处理入口,保持代码逻辑一致性。

替代方案(修改VCL源码)

如果拥有Delphi VCL源码权限,可以修改TWinNotificationCenter的实现,补充操作中心通知激活的回调逻辑:找到TWinNotificationCenter中处理通知激活的代码,添加对Windows操作中心通知激活事件的监听,确保所有场景下的点击都能触发OnReceiveLocalNotification。

内容的提问来源于stack exchange,提问作者Matthias B

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 21:25:09