Nochmal BalloonTip Message Duration - Neuer Ansatz

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 31 Antworten in diesem Thema. Der letzte Beitrag () ist von Dideldum.

    @-Franky-
    Die von mir verwendete Funktion:

    VB.NET-Quellcode

    1. icn_TaskleistenSymbol.ShowBalloonTip(My.Settings.Fragen_Balloontip_Anzeigedauer)
    gehört zur NotifyIcon-Klasse. ;)
    Und aus der NotifyIcon-Klasse hat MS klammheimlich den Parameter geklaut und greift bei der Ausführung nur noch auf die Systemsteuerungs-Werte zurück.
    Anständig, wie MS nun mal ist (und wohl auch aus Abwärtskompatibilitätsgründen) hat MS den Parameter im Aufruf drin gelassen.
    Die Verwender wundern sich dann, warum deren Params nicht übernommen werden.
    Bin auch nur durch Zufall auf einer Webseite darauf gestossen, bei meiner Suche nach den Ursachen...

    @DTF
    Danke Dir! ^^
    Wow, ich habe 15min gebraucht, um Dein Script zu verstehen.
    Bin ja erst seit einem guten Jahr mit .net zugange.
    Das ist aber High-End-Stufe, was Du da zusammengeschnitzt hast.
    Aber klar - so ist es für jeden Verwender absolut idiotensicher. ;)
    Nur halt auch schwer verständlich.

    Dein Tip mit der Frage, wenn sich beide Werte unterscheiden, ist sehr gut - den baue ich ein. :)

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Dideldum“ ()

    Naja, High-End finde ich das noch nicht. Aber wenn du am Ball bleibst, wirst du das bald auch so sehen. Das was ich gemacht habe, ist nichts weiter als minimal erweiterete Nutzung der ComboBox(Richtung Datenbindung). Die meisten Beginner nutzen die ComboBox ja simpel indem sie CBB.Items.Add oder AddRange nutzen. Aber wenn du den Code soweit verstanden hast, bist du auf einem guten Weg.
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D
    @Dideldum Ahh, die NotifyIcon Klasse und da der BalloonTip. Jupp, da dürfte die Duration aus Abwärtskompatibilität noch drin sein. Ab Win8?, zumindest ab Win10 (falls per RegKey nicht wieder umgestellt auf die alten BalloonTips) sollte der Aufruf des NotifyIcon.BalloonTip auf die Windows ToastNotification umgeleitet werden wenn ich nicht falsch liege. Allerdings dann auch nur mit beschränkten Gestalltungsmöglichkeiten. Also wenn ich nicht komplett daneben liege, dann kannst auch gleich direkt die ToastNotification per WinRT nutzen. Da hast auch viel mehr Gestaltungsmöglichkeiten. learn.microsoft.com/en-us/wind…active-toasts?tabs=appsdk
    Mfg -Franky-
    @-Franky-
    wow, danke Dir heftigst! :)
    Von diesem Toastbrot, äh, ToastNotification höre ich eben zum ersten mal.
    Aber was ich in Deinem Link so lese, kommen mir unverschämt gute Ideen dazu, was ich damit in meinem Proggi so alles anstellen könnte.
    Da muss ich wirklich dazu recherchieren, wie ich diese in mein Proggi einbauen kann. ;)
    Die Dinger scheinen ja wollmilchlegende Eiersauen unter den Notifications zu sein.

    EDIT: Wow...
    Muss dazu wohl ein NuGet-Pakets Microsoft.Windows.SDK einbinden und dann noch eine App-ID erstellen.
    Ersteres sollte ja kein Probli sein - aber das mit der App-ID stellt sich wohl nicht gerade als trivial dar. :S

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Dideldum“ ()

    Dideldum schrieb:

    Von diesem Toastbrot, äh, ToastNotification höre ich eben zum ersten mal.
    Aber gesehen hast die sicher schon zigmal. ;) Am einfachsten sind die Standard-Toast. Bei Generic-Toast hast noch mehr Möglichkeiten aber hier müssen auch bestimmte Bedingungen erfüllt sein. Scheduled-Toast die Zeitgesteuert angezeigt werden können usw. Es gibt wohl ein entsprechendes CommunityToolKit dafür, hab das aber bisher nicht genutzt. Hier noch ein Link was so mit der ToastNotification geht: docs.telerik.com/devtools/winf…on/notification-templates
    Mfg -Franky-
    Oh jeh...

    @-Franky-
    habe mir mal das mit der AppID angelesen.
    Anforderungen:
    Desktop Bridge: Eine sauberere Lösung ist die Verwendung der Desktop Bridge (Project Centennial), um Ihre WinForms-oder WPF-Anwendung in eine UWP-App zu konvertieren. Dadurch erhalten Sie eine offizielle AppID im Windows Store, die dann für Toast-Benachrichtigungen verwendet werden kann. Dieser Prozess erfordert jedoch zusätzliche Schritte und die Einreichung Ihrer App in den Microsoft Store.
    Das überreisse ich mal so überhaupt nicht - das scheint mir mehr Arbeit zu sein, als die bisherige Entwicklung meines Programms. ;(
    Und ohne diese AppID keine Toastbrote... =O

    Dideldum schrieb:

    Dadurch erhalten Sie eine offizielle AppID im Windows Store, die dann für Toast-Benachrichtigungen verwendet werden kann. Dieser Prozess erfordert jedoch zusätzliche Schritte und die Einreichung Ihrer App in den Microsoft Store.
    Nö. Ja, Dein Programm benötigt eine AppID. Das ist aber auch nur eine eindeutige GUID oder Name um Dein Programm von den anderen zu unterscheiden bzw. damit eine ToastMessage dein Programm zugeordnet werden kann bzw. damit Du über den ToastManager auch nur auf Deine ToastMessages zugreifen kannst. Hat aber null komma nix mit dem Windows Store, WPF, UWP oder WinForms zu tun. Ich habe ein komplettes VB6 Beispiel für die ToastNotification und das funktioniert bestens. Eigentlich brauch man auch für .NET kein CommunityToolKit dafür. Nur ein paar Kenntnisse in direkter COM Programmierung bzw. da Du noch mit .NET Framework unterwegs bist, kannst Dir auch den Verweis auf die Windows.Winmd einbinden und schon stehen Dir alle Namespaces und Klassen der WinRT zur Verfügung.

    Edit: Fahrplan für Deine erste ToastMessage. Mach Dir erstmal ein neues .NET Framework Testprojekt.
    Ab .NET5! -> Da ab hier keine Verweise auf Winmd's mehr unterstützt werden, kann man wohl das dafür vorgesehene CommunityToolKit nutzen. Ich persöhnlich ziehe es vor direkt mit den WinRT COM Interfaces zu arbeiten
    Bis .NET Framework 4.8.xx! -> Mach Dir einen Verweis auf die "C:\Program Files (x86)\Windows Kits\10\UnionMetadata\10.0.22621.0\Windows.winmd" Wobei die "10.0.22621.0" auch eine andere sein kann. Je nachdem welche Version des Windows SDK bei Dir installiert ist bzw. müsstest Du, falls noch nicht vorhanden, das Windows SDK nachinstallieren.
    2 wichtige Imports

    VB.NET-Quellcode

    1. Imports Windows.Data.Xml.Dom
    2. Imports Windows.UI.Notifications

    1 Const -> Deine AppID. Ist nur zur Identifizierung Deiner Toast.

    VB.NET-Quellcode

    1. Private Const AppID As String = "Toast Notify"

    Ich hab hier noch ein PNG geladen das dann im Toast angezeigt werden soll.

    VB.NET-Quellcode

    1. Private ToastImage As String = New System.Uri(Path.GetFullPath("Logo.png")).AbsoluteUri

    Im Button Click
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    2. 'https://docs.microsoft.com/en-us/uwp/schemas/tiles/toastschema/schema-root
    3. 'https://docs.microsoft.com/en-us/uwp/api/windows.ui.notifications.toasttemplatetype
    4. Dim toastTemplate As ToastTemplateType = ToastTemplateType.ToastImageAndText04
    5. Dim toastXml As XmlDocument = ToastNotificationManager.GetTemplateContent(toastTemplate)
    6. Dim toastNode As IXmlNode = toastXml.SelectSingleNode("/toast")
    7. Dim toastXmlElement As XmlElement = CType(toastNode, XmlElement)
    8. toastXmlElement.SetAttribute("duration", "short")
    9. toastXmlElement.SetAttribute("launch", "toast://my_arguments")
    10. Dim visualNode As IXmlNode = toastXml.SelectSingleNode("/toast/visual")
    11. Dim visualXmlElement As XmlElement = CType(visualNode, XmlElement)
    12. 'visualXmlElement.SetAttribute("addImageQuery", "false")
    13. 'visualXmlElement.SetAttribute("baseUri", "ms-appx:///")
    14. 'visualXmlElement.SetAttribute("branding", "none")
    15. 'visualXmlElement.SetAttribute("lang", "de-DE")
    16. 'visualXmlElement.SetAttribute("version", "1")
    17. Dim bindingNode As IXmlNode = toastXml.SelectSingleNode("/toast/visual/binding")
    18. Dim bindingXmlElement As XmlElement = CType(bindingNode, XmlElement)
    19. 'bindingXmlElement.SetAttribute("addImageQuery", "false")
    20. 'bindingXmlElement.SetAttribute("baseUri", "ms-appx:///")
    21. 'bindingXmlElement.SetAttribute("branding", "none")
    22. 'bindingXmlElement.SetAttribute("fallback", "")
    23. 'bindingXmlElement.SetAttribute("lang", "de-DE")
    24. 'bindingXmlElement.SetAttribute("template", "ToastImageAndText04")
    25. If toastTemplate <= ToastTemplateType.ToastImageAndText04 Then
    26. Dim imageElements As XmlNodeList = toastXml.GetElementsByTagName("image")
    27. Dim imageXmlElement As XmlElement = CType(imageElements(0), XmlElement)
    28. 'imageXmlElement.SetAttribute("addImageQuery", "false")
    29. imageXmlElement.SetAttribute("alt", "Logo")
    30. 'imageXmlElement.SetAttribute("id", "1")
    31. imageXmlElement.SetAttribute("src", ToastImage)
    32. End If
    33. Debug.Print(ToastImage)
    34. Dim textElements As XmlNodeList = toastXml.GetElementsByTagName("text")
    35. Select Case toastTemplate
    36. Case = ToastTemplateType.ToastText01, ToastTemplateType.ToastImageAndText01
    37. textElements(0).AppendChild(toastXml.CreateTextNode("Text"))
    38. Case = ToastTemplateType.ToastText02, ToastTemplateType.ToastImageAndText02
    39. textElements(0).AppendChild(toastXml.CreateTextNode("Titel"))
    40. textElements(1).AppendChild(toastXml.CreateTextNode("Text 1"))
    41. Case = ToastTemplateType.ToastText03, ToastTemplateType.ToastImageAndText03
    42. textElements(0).AppendChild(toastXml.CreateTextNode("Titel"))
    43. textElements(1).AppendChild(toastXml.CreateTextNode("Text 1"))
    44. Case = ToastTemplateType.ToastText04, ToastTemplateType.ToastImageAndText04
    45. textElements(0).AppendChild(toastXml.CreateTextNode("Titel"))
    46. textElements(1).AppendChild(toastXml.CreateTextNode("Text 1"))
    47. textElements(2).AppendChild(toastXml.CreateTextNode("Text 2"))
    48. End Select
    49. ' ms-winsoundevent:Notification.Default
    50. ' ms-winsoundevent:Notification.IM
    51. ' ms-winsoundevent:Notification.Mail
    52. ' ms-winsoundevent:Notification.Reminder
    53. ' ms-winsoundevent:Notification.SMS
    54. ' ms-winsoundevent:Notification.Looping.Alarm
    55. ' ms-winsoundevent:Notification.Looping.Alarm2
    56. ' ms-winsoundevent:Notification.Looping.Alarm3
    57. ' ms-winsoundevent:Notification.Looping.Alarm4
    58. ' ms-winsoundevent:Notification.Looping.Alarm5
    59. ' ms-winsoundevent:Notification.Looping.Alarm6
    60. ' ms-winsoundevent:Notification.Looping.Alarm7
    61. ' ms-winsoundevent:Notification.Looping.Alarm8
    62. ' ms-winsoundevent:Notification.Looping.Alarm9
    63. ' ms-winsoundevent:Notification.Looping.Alarm10
    64. ' ms-winsoundevent:Notification.Looping.Call
    65. ' ms-winsoundevent:Notification.Looping.Call2
    66. ' ms-winsoundevent:Notification.Looping.Call3
    67. ' ms-winsoundevent:Notification.Looping.Call4
    68. ' ms-winsoundevent:Notification.Looping.Call5
    69. ' ms-winsoundevent:Notification.Looping.Call6
    70. ' ms-winsoundevent:Notification.Looping.Call7
    71. ' ms-winsoundevent:Notification.Looping.Call8
    72. ' ms-winsoundevent:Notification.Looping.Call9
    73. ' ms-winsoundevent:Notification.Looping.Call10
    74. Dim audioXmlElement As XmlElement = toastXml.CreateElement("audio")
    75. audioXmlElement.SetAttribute("src", "ms-winsoundevent:Notification.Looping.Alarm")
    76. 'audioXmlElement.SetAttribute("loop", "false")
    77. 'audioXmlElement.SetAttribute("silent", "false")
    78. toastNode.AppendChild(audioXmlElement)
    79. Dim commandsXmlElement As XmlElement = toastXml.CreateElement("commands")
    80. commandsXmlElement.SetAttribute("scenario", "alarm")
    81. Dim commandsNode As IXmlNode = toastNode.AppendChild(commandsXmlElement)
    82. Dim commandXmlElement0 As XmlElement = toastXml.CreateElement("command")
    83. commandXmlElement0.SetAttribute("id", "dismiss")
    84. commandXmlElement0.SetAttribute("arguments", "dismiss")
    85. commandsNode.AppendChild(commandXmlElement0)
    86. Dim commandXmlElement1 As XmlElement = toastXml.CreateElement("command")
    87. commandXmlElement1.SetAttribute("id", "snooze")
    88. commandXmlElement1.SetAttribute("arguments", "snooze")
    89. commandsNode.AppendChild(commandXmlElement1)
    90. 'https://docs.microsoft.com/en-us/uwp/api/windows.ui.notifications.toastnotification
    91. Dim toast As ToastNotification = New ToastNotification(toastXml)
    92. With toast
    93. '.Content
    94. '.Data
    95. .ExpirationTime = DateTimeOffset.Now.AddDays(1)
    96. '.ExpiresOnReboot = False
    97. .Group = "Group"
    98. '.NotificationMirroring = NotificationMirroring.Disabled
    99. '.Priority = ToastNotificationPriority.High
    100. '.RemoteId ="ID"
    101. '.SuppressPopup=True
    102. .Tag = "123456"
    103. End With
    104. AddHandler toast.Activated, AddressOf ToastActivated
    105. AddHandler toast.Dismissed, AddressOf ToastDismissed
    106. AddHandler toast.Failed, AddressOf ToastFailed
    107. TextBox1.Text = Replace(toast.Content.GetXml, "><", ">" & vbNewLine & "<")
    108. 'https://docs.microsoft.com/en-us/uwp/api/windows.ui.notifications.toastnotificationmanager
    109. ToastNotificationManager.CreateToastNotifier(AppID).Show(toast)
    110. End Sub


    Die Event Handler
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub ToastActivated(ByVal sender As ToastNotification, ByVal e As Object)
    2. ClearText()
    3. ChangeText("The user activated the toast.")
    4. ChangeText("Toastgroup: " & sender.Group)
    5. ChangeText("Toasttag: " & sender.Tag)
    6. ChangeText("ExpirationTime: " & sender.ExpirationTime.ToString)
    7. If TypeOf e Is ToastActivatedEventArgs Then
    8. Dim args As ToastActivatedEventArgs = CType(e, ToastActivatedEventArgs)
    9. If Not String.IsNullOrWhiteSpace(args.Arguments) Then
    10. Dim toastLaunch As Match = Regex.Match(args.Arguments, "^toast://(?<arguments>.*)$")
    11. Dim toastActivationArgs = toastLaunch.Groups("arguments")
    12. If toastActivationArgs.Success Then
    13. ChangeText("ActivationArgs: " & toastActivationArgs.Value)
    14. End If
    15. ChangeText("Arguments: " & args.Arguments)
    16. End If
    17. End If
    18. ChangeText("")
    19. End Sub
    20. Private Sub ToastDismissed(ByVal sender As ToastNotification, ByVal e As ToastDismissedEventArgs)
    21. ClearText()
    22. Select Case e.Reason
    23. Case ToastDismissalReason.ApplicationHidden
    24. ChangeText("The app hide the toast using ToastNotifier.Hide")
    25. Case ToastDismissalReason.UserCanceled
    26. ChangeText("The user dismissed the toast")
    27. Case ToastDismissalReason.TimedOut
    28. ChangeText("The toast has timed out")
    29. End Select
    30. ChangeText("Toastgroup: " & sender.Group)
    31. ChangeText("Toasttag: " & sender.Tag)
    32. ChangeText("ExpirationTime: " & sender.ExpirationTime.ToString)
    33. ChangeText("")
    34. End Sub
    35. Private Sub ToastFailed(ByVal sender As ToastNotification, ByVal e As ToastFailedEventArgs)
    36. ClearText()
    37. ChangeText("The toast encountered an error. Error: " & e.ErrorCode.Message)
    38. ChangeText("Toastgroup: " & sender.Group)
    39. ChangeText("Toasttag: " & sender.Tag)
    40. ChangeText("ExpirationTime: " & sender.ExpirationTime.ToString)
    41. ChangeText("")
    42. End Sub


    Hier ein Beispiel für ein Generic-Toast. Dafür müssen aber bestimmte Bedingungen erfüllt sein. Komme ich vllt. später drauf zurück. Was ich aber damit zeigen möchte ist, anstatt den XML über die Windows.Data.Xml.Dom zusammen zu bauen, kannst auch gleich direkt einen XML-String übergeben.
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
    2. Dim toastXML As New Windows.Data.Xml.Dom.XmlDocument
    3. toastXML.LoadXml("<toast launch='action'>" &
    4. "<visual>" &
    5. "<binding template='ToastGeneric'>" &
    6. "<text>Text1</text>" &
    7. "<text>Text2</text>" &
    8. "</binding>" &
    9. "</visual>" &
    10. "</toast>")
    11. Dim toast As New ToastNotification(toastXML)
    12. With toast
    13. '.Content
    14. '.Data
    15. .ExpirationTime = DateTimeOffset.Now.AddDays(1)
    16. '.ExpiresOnReboot = False
    17. .Group = "Group"
    18. '.NotificationMirroring = NotificationMirroring.Disabled
    19. '.Priority = ToastNotificationPriority.High
    20. '.RemoteId ="ID"
    21. '.SuppressPopup=True
    22. .Tag = "123457"
    23. End With
    24. AddHandler toast.Activated, AddressOf ToastActivated
    25. AddHandler toast.Dismissed, AddressOf ToastDismissed
    26. AddHandler toast.Failed, AddressOf ToastFailed
    27. TextBox1.Text = Replace(toast.Content.GetXml, "><", ">" & vbNewLine & "<")
    28. ToastNotificationManager.CreateToastNotifier(AppID).Show(toast)
    29. End Sub


    Denke das das für den Anfang, wie man Standard-Toast erstellt, reicht. Für Generic-Toast müsstest Du eine Shortcut im Startmenü anlegen und Deine App als COM-Server registrieren wofür auch die AppID und eine AppActivatorCLSID benötigt werden. Ansonsten findest ja im Button1_Click weitere Links zu den Toast.
    Mfg -Franky-

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „-Franky-“ ()

    Dideldum schrieb:

    Und ohne diese AppID keine Toastbrote...


    Man kann sich auch selbst so ein Toast machen. Man nehme Mehl, Wasser, Salz, Hefe......

    Ach ne, man nehme ein Form und bastelt sich ein dynamisches UI drauf. Bedenkt das es User gibt(ich z.B.), die solche ToastsNotifications nervig finden und Windows so eingestellt haben, das Apps diese nicht mit den Toasts nerven. Ich lasse mir nur das absolut Notwendige anzeigen. Windows kann nicht wissen welche Meldungen wichtig für den User sind, von daher finde ich eine eigene Implementation besser, denn da hat man die volle Kontrolle und kann den User das einstellen lasse, bietet man eine Option an, "Nur wichtige Meldungen anzeigen", kann der User trotzdem informiert werden.
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „DTF“ ()

    DTF schrieb:

    die solche ToastsNotifications nervig finden

    Ja klar, man sollte den User nicht mit ToastMessages überschwemmen. ;)

    DTF schrieb:

    Man kann sich auch selbst so ein Toast machen. Man nehme Mehl, Wasser, Salz, Hefe......
    ...und zum Nachtisch gibt es ... Nee was mir gestern Abend noch so durch den Kopf ging ist: Wenn man sich nun ein eigenes PopUp bastelt, worüber man als User nun gar keine Kontrolle hat wie oft der aufplöpt, kann man den User auch mit Messages überschwemmen. Dann doch eher eine Lösung wo der User die Möglichkeit besitzt die ToastMessages einzuschränken. Na dann, guten Appetit. ;)
    Mfg -Franky-

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „-Franky-“ ()

    Hi @DTF und @-Franky-
    Da habt Ihr ganz recht. ;)
    Mich nerven solche Popups auch.

    Daher haben in meinem Proggi die User volle Kontrolle über die nicht unbedingt erforderlichen Anzeigen. ^^
    Die nicht überlebensnotwendigen Ausgaben können die User deaktivieren und z.T. sogar auswählen, ob sie die gewollten in einem Fenster (mit "OK"-Bestätigung) oder als selbstlöschendes Ballöönchen haben wollen.
    Bilder
    • Tab_15_Sicherheitsfragen.jpg

      149,89 kB, 1.006×611, 17 mal angesehen
    Hi @-Franky-
    Ups, fast überlesen, Deine Anleitung.
    Danke Dir vielmals dafür! :)
    Habe mir den Link gesichert.
    Im Moment klappt es ja noch mit meinen NotifyIcons.

    Deine Lösung mit den Toasts kommt dann - so ich es hingefummelt bekomme - in einem Update, welches dann mehr Funktionen ins Proggi bringt.

    Im Moment plage ich mich eher mit der Übersetzung von 241 Dokumenten im Hilfe-Archiv DE, um diese für das englische Hilfe-Archiv zu übersetzen.
    Eine Sch... öne Arbeit... ;(