Как добавить текстовый узел в тост-уведомление

Это тост-уведомление очень хорошо работает с рабочего стола с XE8 с Windows 10, но я не могу понять, как добавить текстовую строку к уведомлению. iTitle отображается, но iMessage нет. Это все новое для меня, поэтому я не знаю, какое направление преследовать.

Пятое редактирование....

Превосходная процедура Remy для шоу-тоста является большим улучшением по сравнению с оригинальным кодом Embaracdero, но я не думаю, что Remy на самом деле тестировал код, потому что он не будет компилироваться так, как написано. Мне пришлось изменить TWindowString на TWindowsString и IXmlNode на Xml_Dom_IXmlNode, чтобы заставить его скомпилировать.

Следующее фактически компилируется, но генерирует нарушение прав доступа в функции GetActivationFactory.

Если мы сможем заставить это работать правильно, это будет большим улучшением по сравнению с оригинальным кодом Embarcadero и должно быть полезным для других разработчиков.

 procedure TForm1.ShowToast(const AMessage: String; const ATitle: String = '');
{ Send a Toast Notification }
var
  LINotificationManagerStatics: IToastNotificationManagerStatics;
  LToast: IToastNotification;
  LToastFactory: IToastNotificationFactory;
  LToastNotifier: IToastNotifier;
  LToastTemplateType: ToastTemplateType;
  LAccepted: TAcceptedEventHandler;
  LXMLTemplate: Xml_Dom_IXmlDocument;
  iTextNode: Xml_Dom_IXmlNode;
  LTextNodeList: Xml_Dom_IXmlNodeList;

  function GetActivationFactory(const ClassId: String; const Iid: String): IInspectable;
  begin
    OleCheck(RoGetActivationFactory(TWindowsString(ClassId), TGUID.Create(Iid), Result));
   // This produces an access violation at run time
  end;

begin
  LINotificationManagerStatics := GetActivationFactory(SToastNotificationManager, '{50AC103F-D235-4598-BBEF-98FE4D1A3AD4}') as IToastNotificationManagerStatics;
  LToastNotifier := LINotificationManagerStatics.CreateToastNotifier(TWindowsString(Edit1.Text));
  if ATitle <> '' then begin
    LToastTemplateType := ToastTemplateType.ToastText02;
  end else begin
    LToastTemplateType := ToastTemplateType.ToastText01;
  end;
  LXMLTemplate := LINotificationManagerStatics.GetTemplateContent(LToastTemplateType);
  LTextNodeList := LXMLTemplate.getElementsByTagName(TWindowsString('text'));
  if ATitle <> '' then
  begin
    LTextNodeList.Item(0).AppendChild(LXMLTemplate.CreateTextNode(TWindowsString(ATitle)) as Xml_Dom_IXmlNode);
    iTextNode := LTextNodeList.Item(1);
  end else begin
    iTextNode := LTextNodeList.Item(0);
  end;
  iTextNode.AppendChild(LXMLTemplate.CreateTextNode(TWindowsString(AMessage)) as Xml_Dom_IXmlNode);
  LToastFactory := GetActivationFactory(SToastNotification, '{04124B20-82C6-4229-B109-FD9ED4662B53}') as IToastNotificationFactory;
  LToast := LToastFactory.CreateToastNotification(LXMLTemplate);
  LAccepted := TAcceptedEventHandler.Create;
  LToast.add_Activated(LAccepted);
  LToastNotifier.Show(LToast);
end;

2 ответа

Решение

После большой отладки я наконец-то успешно получил уведомление о тосте для отображения заголовка и сообщения. Оказывается, мне пришлось использовать модифицированную версию ответа Реми в сочетании с некоторыми оригинальными демонстрационными кодами Embaracdero, чтобы заставить его работать.

Спасибо, Реми! Я не думал, что доберусь туда, но наконец-то сделал. Чтобы спасти других, кто пытается сделать это, много горя, мой рабочий код показан ниже:

procedure TForm1.ShowToast(const AMessage: String; const ATitle: String = '');
{ Send a Toast Notification }
var
  LINotificationManagerStatics: IToastNotificationManagerStatics;
  LToast: IToastNotification;
  LToastFactory: IToastNotificationFactory;
  LToastNotifier: IToastNotifier;
  LClassId: HString;
  LAccepted: TAcceptedEventHandler;
  LXMLTemplate: Xml_Dom_IXmlDocument;
  iTextNode: Xml_Dom_IXmlNode;
  LTextNodeList: Xml_Dom_IXmlNodeList;
  LTagName: HString;
  LTitle: HString;
  LMessage: HString;

  function GetActivationFactory(const ClassId: String; const Iid: String)
    : IInspectable;
  begin
    if Succeeded(WindowsCreateString(PWideChar(ClassId), Length(ClassId),
      LClassId)) then
      OleCheck(RoGetActivationFactory(LClassId, TGUID.Create(Iid), Result));
  end;

begin
  LINotificationManagerStatics := GetActivationFactory
    (SToastNotificationManager, '{50AC103F-D235-4598-BBEF-98FE4D1A3AD4}')
    as IToastNotificationManagerStatics;
  if Succeeded(WindowsCreateString(PWideChar(NotificationTitle1.Text),
    Length(NotificationTitle1.Text), LClassId)) then
    LToastNotifier := LINotificationManagerStatics.CreateToastNotifier
      (LClassId);
  LXMLTemplate := LINotificationManagerStatics.GetTemplateContent
    (ToastTemplateType.ToastText02);
  if Succeeded(WindowsCreateString(PWideChar('text'), Length('text'), LTagName))
  then
    LTextNodeList := LXMLTemplate.getElementsByTagName(LTagName);
  if ATitle <> '' then
  begin
    if Succeeded(WindowsCreateString(PWideChar(ATitle), Length(ATitle), LTitle))
    then
      LTextNodeList.Item(0).AppendChild(LXMLTemplate.CreateTextNode(LTitle)
        as Xml_Dom_IXmlNode);
    iTextNode := LTextNodeList.Item(1);
  end
  else
  begin
    iTextNode := LTextNodeList.Item(0);
  end;
  if Succeeded(WindowsCreateString(PWideChar(AMessage), Length(AMessage),
    LMessage)) then
    iTextNode.AppendChild(LXMLTemplate.CreateTextNode(LMessage)
      as Xml_Dom_IXmlNode);
  LToastFactory := GetActivationFactory(SToastNotification,
    '{04124B20-82C6-4229-B109-FD9ED4662B53}') as IToastNotificationFactory;
  LToast := LToastFactory.CreateToastNotification(LXMLTemplate);
  LAccepted := TAcceptedEventHandler.Create;
  LToast.add_Activated(LAccepted);
  LToastNotifier.Show(LToast);
end;

Использование:

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowToast(NotificationMessage1.Text, NotificationTitle1.Text);
end;

IXmlDocument.CreateTextNode() создает и возвращает новый текстовый узел, но НЕ добавляет его в документ XML. Вы должны добавить это отдельно. Это даже продемонстрировано в документации Toast:

Быстрый старт: отправка всплывающего уведомления (HTML)

Быстрый старт: отправка уведомления о тосте (XAML)

Например:

var
  ...
  LTagName: HString;

...    
if Succeeded(WindowsCreateString(PWideChar(iMessage), Length(iMessage), LString3)) then
try
  if Succeeded(WindowsCreateString(PWideChar('text'), 4, LTagName)) then
  try
    LXMLTemplate.getElementsByTagName(LTagName).Item(0).AppendChild(LXMLTemplate.CreateTextNode(LString3) as IXmlNode);
    ...
  finally
    WindowsDeleteString(LTagName);
  end;
  ...
finally
  WindowsDeleteString(LString3);
end;
...

В качестве альтернативы используйте IXmlNode.InnerText собственность вместо IXmlDocument.CreateTextNode() метод:

LXMLTemplate.getElementsByTagName(LTagName).Item(0).InnerText := LString3;

Честно говоря, пример Embarcadero, на котором вы основали свой код, немного беспорядок. Это может использовать серьезную очистку.

Попробуйте что-то вроде этого:

uses
  ...,
  System.SysUtils,
  System.Win.ComObj,
  Winapi.Data,
  System.WinrtHelpers; // see https://github.com/tgerdes/DelphiWinRT/blob/master/System.WinrtHelpers.pas

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowToast('The recycle bin is empty', 'Recycle Bin Is Empty');
end;

procedure TForm1.ShowToast(const AMessage: String; const ATitle: String = '');
{ Send a Toast Notification }
var
  LINotificationManagerStatics: IToastNotificationManagerStatics;
  LToast: IToastNotification;
  LToastFactory: IToastNotificationFactory;
  LToastNotifier: IToastNotifier;
  LToastTemplateType: ToastTemplateType;
  LAccepted: TAcceptedEventHandler;
  LXMLTemplate: Xml_Dom_IXmlDocument;
  iTextNode: Xml_Dom_IXmlNode;
  LTextNodeList: Xml_Dom_IXmlNodeList;

  function GetActivationFactory(const ClassId: String; const Iid: String): IInspectable;
  begin
    OleCheck(RoGetActivationFactory(TWindowsString(ClassId), TGUID.Create(Iid), Result));
  end;

begin
  LINotificationManagerStatics := GetActivationFactory(SToastNotificationManager, '{50AC103F-D235-4598-BBEF-98FE4D1A3AD4}') as IToastNotificationManagerStatics;
  LToastNotifier := LINotificationManagerStatics.CreateToastNotifier(TWindowString(Edit1.Text));
  if ATitle <> '' then begin
    LToastTemplateType := ToastTemplateType.ToastText02;
  end else begin
    LToastTemplateType := ToastTemplateType.ToastText01;
  end;
  LXMLTemplate := LINotificationManagerStatics.GetTemplateContent(LToastTemplateType);
  LTextNodeList := LXMLTemplate.getElementsByTagName(TWindowString('text'));
  if ATitle <> '' then
  begin
    LTextNodeList.Item(0).AppendChild(LXMLTemplate.CreateTextNode(TWindowString(ATitle)) as IXmlNode);
    iTextNode := LTextNodeList.Item(1);
  end else begin
    iTextNode := LTextNodeList.Item(0);
  end;
  iTextNode.AppendChild(LXMLTemplate.CreateTextNode(TWindowString(AMessage)) as IXmlNode);
  LToastFactory := GetActivationFactory(SToastNotification, '{04124B20-82C6-4229-B109-FD9ED4662B53}') as IToastNotificationFactory;
  LToast := LToastFactory.CreateToastNotification(LXMLTemplate);
  LAccepted := TAcceptedEventHandler.Create;
  LToast.add_Activated(LAccepted);
  LToastNotifier.Show(LToast);
end;
Другие вопросы по тегам