Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Lesedauer 7 Min.

Notifications unter WPF: Toast für dich

Benachrichtigungen für den Anwender mit den Bordmitteln von Windows anzeigen.
Zugegeben: Manchmal nerven die kleinen Fensterchen, die plötzlich aufpoppen und mitteilen, dass Sie gerade der glückliche Gewinner von 34 Millionen US-Dollar geworden sind, wenn, ja wenn Sie nur vorher … Die kleinen Fensterchen werden als Toast Notifications bezeichnet. Der Artikel erklärt, wie Sie in Ihren Windows-Anwendungen oder in Ihren Windows-Diensten Toast Notifications benutzen, um den Anwender über Ereignisse zu informieren. Frameworks für diese Aufgabe gibt es wie Sand am Meer. Hier soll es aber um die Benutzung der vom Betriebssystem bereitgestellten Funktionen gehen. Sie erfahren, welche Systemvoraussetzungen nötig sind, welche Bibliotheken in Ihrem Projekt einzubinden sind, wie eine Toast Notification aufgebaut ist und wie Sie sogar mit dem Anwender in Interak­tion treten können.

Ein Blick zurück

Viele C#- und VB.NET-Entwickler wählten die MessageBox, wenn es darum ging, den Anwender mit Informationen zu versorgen, oder sogar, um von ihm eine Antwort zu bekommen. Das hatte natürlich immer den Nachteil, dass das Programm erst weiterarbeitete, wenn das Fenster wieder geschlossen war. Für Windows-Dienste war die Benutzung der MessageBox deshalb von vornherein keine Option. Man ging also dazu über, eigene Formulare beziehungsweise Fenster zu gestalten, um diese dem Anwender anzuzeigen.
Mit Windows 8, Windows 8 RT, Windows Phone 8 und dem Metro-Design legte Microsoft den Grundstein für die Toast Notifications – ein Vorstoß, der bei den Anwendern nicht auf große Gegenliebe stieß. Während unter Windows 8 eine Benachrichtigung noch aus maximal zwei Textzeilen und optional einem Bild bestehen durfte (siehe Bild1), kann sie heute unter Windows 10 nahezu frei gestaltet werden (siehe Bild2).

Einstellungen in Visual Studio

Lassen Sie uns nun an einem Beispiel zeigen, wie man mit Visual Studio eine WPF-Anwendung für das Erstellen und Versenden von Toast Notifications vorbereitet. Sie legen mit Visual Studio 2015 oder 2017 (die kostenfreie Community Edition [1] ist völlig ausreichend) ein neues WPF-Projekt an. Als Ziel-Framework wird 4.6.2 ausgewählt. Als Nächstes benötigen Sie Referenzen auf folgende Windows-Runtime-Bibliotheken:
  • Windows.Data.winmd
  • Windows.Foundation.winmd
  • Window.UI.winmd
Diese sind in der Liste der verfügbaren Bibliotheken des Verweis-Managers (Bild3, linke Seite) nicht enthalten. Auf Ihrer Suche nach den Dateien werden Sie im Verzeichnis C:\Windows\System32\WinMetadata fündig. Wenn Sie nun dem Projekt die Verweise auf die Dateien hinzufügen (siehe auch den Kasten Windows-Runtime-Bibliotheken), zeigt Vi­sual Studio Warnungen an (Bild4). Das war zu erwarten, denn die WINMD-Dateien (WindowsMetaData) wurden einst für das abgespeckte Windows 8 RT erschaffen, sind also zum Beispiel nicht auf einem Windows-7-Rechner vorhanden.

Windows-Runtime-Bibliotheken

Die Bibliotheken im Verzeichnis C:\Windows\System32\WinMetadata\ sind Dateien, die durch das Betriebssystem bereitgestellt werden. Dabei sind die unterschiedlichen Namensräume auf verschiedene Dateien aufgeteilt. Dieser Artikel beschreibt Features, die nur funktionieren, wenn auf dem Zielrechner das Windows 10 Anniversary Update installiert ist. Als Softwareentwickler haben Sie wahrscheinlich das aktuellste Windows SDK installiert. Sollte das der Fall sein, finden Sie unter C:\Program Files (x86)\Windows Kits\10\UnionMetadata\ die Datei Windows.winmd. Darin sind alle Namensräume zusammengefasst enthalten. Diese Datei wird im Verweis-Manager nicht aufgelistet, kann aber dennoch direkt ausgewählt werden.
Neben der Festlegung auf das Ziel-Framework 4.6.2 muss das Projekt also noch für ein bestimmtes Betriebssystem konfiguriert werden. In den Projekt-Eigenschaften lässt sich dazu aber keine Einstellungsmöglichkeit finden. Darum tragen Sie die Angabe im nächsten Schritt ma­nuell in die Projektdatei (.csproj beziehungsweise .vbproj) ein. Dazu speichern Sie das Projekt und wählen über das Kontextmenü (rechte Maustaste) der Projektdatei den Menüeintrag Projekt entladen aus.
Erneut wird über das Kontextmenü der Eintrag Bearbeiten Projektname.csproj angeklickt. Jetzt ist ein XML-formatierter Text zu sehen. In der ersten PropertyGroup findet sich das Tag TargetFrameworkVersion. Unter diesem wird nun manuell der Eintrag TargetPlatformVersion eingefügt (Bild 5). Im Beispiel legen wir uns auf die Version 10.0 fest. Weitere gültige Werte wären 8.0 und 8.1.
Nach dem Speichern der Änderung und dem Aufruf von Projekt erneut laden aus dem Kontextmenü ist die Warnung in der Fehlerliste verschwunden. Der richtige Weg wäre also gewesen, erst das Flag zur TargetPlatformVersion in der Projektdatei zu setzen und dann über den Verweis-Manager die Bibliotheken dem Projekt hinzuzufügen, denn wie auf Bild 3 (rechte Seite) zu sehen ist, steht nun die Registerkarte Universal Windows zur Verfügung, um Windows-Runtime-Bibliotheken auszuwählen.
Listing 1: Toast anzeigen
<span class="hljs-built_in">void</span> <span class="hljs-type">ShowNotification</span>() { <br/>  <span class="hljs-keyword">var</span> templateType = <br/>    <span class="hljs-type">ToastTemplateType</span>.<span class="hljs-type">ToastImageAndText04</span>; <br/>  <span class="hljs-keyword">var</span> <span class="hljs-keyword">template</span> = <span class="hljs-type">ToastNotificationManager</span>.<span class="hljs-type">GetTemplate</span><br/>    <span class="hljs-type">Content</span>(templateType); <br/> <br/>  <span class="hljs-keyword">template</span>.<span class="hljs-type">GetElementsByTagName</span>(<span class="hljs-string">"text"</span>)[<span class="hljs-number">0</span>] <br/>    .<span class="hljs-type">InnerText</span> = <span class="hljs-string">"Hallo und herzlich willkommen zum "</span> + <br/>      <span class="hljs-string">"dotnetpro-Artikel 'ToastNotifications'"</span>; <br/> <br/>  <span class="hljs-keyword">template</span>.<span class="hljs-type">GetElementsByTagName</span>(<span class="hljs-string">"text"</span>)[<span class="hljs-number">1</span>] <br/>    .<span class="hljs-type">InnerText</span> = <span class="hljs-string">"Schön, dass ich euch für diesen </span><br/><span class="hljs-string">      Beitrag "</span> + <br/>    <span class="hljs-string">"in der dotnetpro begeistern konnte."</span>; <br/> <br/>  ((<span class="hljs-type">XmlElement</span>)<span class="hljs-keyword">template</span>.<span class="hljs-type">GetElementsByTagName</span>(<span class="hljs-string">"image"</span>)<br/>    [<span class="hljs-number">0</span>]) <br/>      .<span class="hljs-type">SetAttribute</span>(<span class="hljs-string">"src"</span>, <span class="hljs-string">"file:///"</span> + <span class="hljs-type">Path</span>.<br/>        <span class="hljs-type">GetFullPath</span>(<span class="hljs-string">"Andy.png"</span>)); <br/> <br/>  <span class="hljs-keyword">var</span> notification = new <span class="hljs-type">ToastNotification</span>(<span class="hljs-keyword">template</span>); <br/>  <span class="hljs-keyword">var</span> applicationId = <span class="hljs-string">"ToastNotification - TestApp"</span>; <br/>  <span class="hljs-keyword">var</span> manager = <span class="hljs-type">ToastNotificationManager</span>.<span class="hljs-type">CreateToast</span><br/>    <span class="hljs-type">Notifier</span>(applicationId); <br/>  manager.<span class="hljs-type">Show</span>(notification); <br/>}  

Syntax einer Notification

Die Voraussetzungen sind nun geschaffen und der ersten Benachrichtigung steht nichts mehr im Wege. Nach dem Aufruf des Codes aus Listing 1 sollte auf dem Bildschirm die Benachrichtigung angezeigt werden, wie es in Bild 1 dargestellt ist. Dabei handelt es sich um die einfachste Form einer Benachrichtigung, die aus maximal zwei Texten und einem optionalem Bild besteht. Unter Windows 8/RT sahen alle Benachrichtigungen so aus.Unter Windows 10 gibt es umfangreichere Möglichkeiten, um das Aussehen einer Benachrichtigung zu beeinflussen, wie eindrucksvoll durch Bild 2 demonstriert wird. Die Grundlage einer jeden Benachrichtigung ist ein XML-Text. Dieser wird entweder aus einer Reihe von Templates ausgewählt, wobei anschließend die Platzhalter mit Werten befüllt werden, so wie in Listing1 bereits gezeigt, oder es wird dynamisch ein XML-Text zusammengesetzt. Dazu ist es notwendig, die folgende gültige Syntax eines XML-Textes zu kennen:
<span class="hljs-section">&lt;toast&gt;</span> <span class="hljs-section">&lt;visual /&gt;</span> <span class="hljs-section">&lt;actions /&gt;</span> <span class="hljs-section">&lt;audio /&gt;</span> <span class="hljs-section">&lt;/toast&gt;</span> 
Der Abschnitt <visual> enthält Texte und Bilder, während im Abschnitt <actions> Eingabefelder, Auswahlboxen und Schaltflächen definiert werden. Bei der Einblendung jeder Benachrichtigung ist ein akustisches Signal zu hören. Möchte man von dem Standard­signal abweichen, bietet der Abschnitt <audio> dafür die passenden Möglichkeiten. ­Einen wirklich umfassenden Überblick über die gültigen Elemente geben die Webseiten unter [2] und [3].
Listing 2: Dynamisch erzeugtes Template
&lt;span class="hljs-keyword"&gt;private&lt;/span&gt; void ShowDotnetproNotification() { &lt;br/&gt;  &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; binding = &lt;span class="hljs-keyword"&gt;new&lt;/span&gt; &lt;span class="hljs-type"&gt;ToastBindingGeneric&lt;/span&gt;(); &lt;br/&gt;  binding.HeroImage = &lt;span class="hljs-keyword"&gt;new&lt;/span&gt; &lt;span class="hljs-type"&gt;ToastGenericHeroImage&lt;/span&gt;() { &lt;br/&gt;    Source = &lt;span class="hljs-string"&gt;"file:///"&lt;/span&gt; + Path.GetFullPath(&lt;br/&gt;      &lt;span class="hljs-string"&gt;"dotnetpro2.jpg"&lt;/span&gt;) }; &lt;br/&gt;  binding.AppLogoOverride = &lt;span class="hljs-keyword"&gt;new&lt;/span&gt; &lt;span class="hljs-type"&gt;ToastGenericAppLogo&lt;/span&gt;() &lt;br/&gt;    { Source = &lt;span class="hljs-string"&gt;"file:///"&lt;/span&gt; + Path.&lt;br/&gt;      GetFullPath(&lt;span class="hljs-string"&gt;"dotnetpro120x120.jpg"&lt;/span&gt;), &lt;br/&gt;        HintCrop = ToastGenericAppLogoCrop.Circle }; &lt;br/&gt;  binding.Children.Add(&lt;span class="hljs-keyword"&gt;new&lt;/span&gt; &lt;span class="hljs-type"&gt;AdaptiveText&lt;/span&gt;() { Text = &lt;br/&gt;    &lt;span class="hljs-string"&gt;"JETZT kostenlos probelesen"&lt;/span&gt; }); &lt;br/&gt;  binding.Children.Add(&lt;span class="hljs-keyword"&gt;new&lt;/span&gt; &lt;span class="hljs-type"&gt;AdaptiveText&lt;/span&gt;() { Text = &lt;br/&gt;    &lt;span class="hljs-string"&gt;"dotnetpro ist die führende deutschsprachige &lt;/span&gt;&lt;br/&gt;&lt;span class="hljs-string"&gt;    Wissensplattform "&lt;/span&gt; + &lt;br/&gt;    &lt;span class="hljs-string"&gt;"für professionelle Software-Entwickler."&lt;/span&gt; }); &lt;br/&gt;  binding.Attribution = &lt;span class="hljs-keyword"&gt;new&lt;/span&gt; &lt;span class="hljs-type"&gt;ToastGenericAttribution&lt;/span&gt;&lt;br/&gt;    Text() { Text = &lt;span class="hljs-string"&gt;"AboService"&lt;/span&gt; }; &lt;br/&gt; &lt;br/&gt;  &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; actions = &lt;span class="hljs-keyword"&gt;new&lt;/span&gt; &lt;span class="hljs-type"&gt;ToastActionsCustom&lt;/span&gt;(); &lt;br/&gt;  &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; &lt;span class="hljs-keyword"&gt;new&lt;/span&gt;&lt;span class="hljs-type"&gt;sInput&lt;/span&gt; = &lt;span class="hljs-keyword"&gt;new&lt;/span&gt; &lt;span class="hljs-type"&gt;ToastTextBox&lt;/span&gt;(&lt;span class="hljs-string"&gt;"news"&lt;/span&gt;) &lt;br/&gt;    { Title = &lt;span class="hljs-string"&gt;"Newsletter"&lt;/span&gt;, PlaceholderContent = &lt;br/&gt;      &lt;span class="hljs-string"&gt;"Email-Adresse"&lt;/span&gt; }; &lt;br/&gt;  actions.Buttons.Add(&lt;span class="hljs-keyword"&gt;new&lt;/span&gt; &lt;span class="hljs-type"&gt;ToastButton&lt;/span&gt;(&lt;span class="hljs-string"&gt;"sent"&lt;/span&gt;, &lt;br/&gt;    &lt;span class="hljs-string"&gt;"sent"&lt;/span&gt;) { TextBoxId = &lt;span class="hljs-string"&gt;"news"&lt;/span&gt;, &lt;br/&gt;      ImageUri = &lt;span class="hljs-string"&gt;"file:///"&lt;/span&gt; + Path.&lt;br/&gt;        GetFullPath(&lt;span class="hljs-string"&gt;"MailSent.png"&lt;/span&gt;) }); &lt;br/&gt;  actions.Inputs.Add(&lt;span class="hljs-keyword"&gt;new&lt;/span&gt;&lt;span class="hljs-type"&gt;sInput&lt;/span&gt;); &lt;br/&gt; &lt;br/&gt;  &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; aboInput = &lt;span class="hljs-keyword"&gt;new&lt;/span&gt; &lt;span class="hljs-type"&gt;ToastSelectionBox&lt;/span&gt;(&lt;span class="hljs-string"&gt;"abotype"&lt;/span&gt;) { &lt;br/&gt;    Title = &lt;span class="hljs-string"&gt;"Wählen Sie Ihr Abonnement"&lt;/span&gt;, &lt;br/&gt;      DefaultSelectionBoxItemId = &lt;span class="hljs-string"&gt;"gratis"&lt;/span&gt; }; &lt;br/&gt;  aboInput.Items.Add(&lt;span class="hljs-keyword"&gt;new&lt;/span&gt; &lt;span class="hljs-type"&gt;ToastSelectionBoxItem&lt;/span&gt;(&lt;br/&gt;    &lt;span class="hljs-string"&gt;"gratis"&lt;/span&gt;, &lt;span class="hljs-string"&gt;"Gratis-Abonnement (0,00 € / &lt;/span&gt;&lt;br/&gt;&lt;span class="hljs-string"&gt;      2 Ausgaben)"&lt;/span&gt;)); &lt;br/&gt;  aboInput.Items.Add(&lt;span class="hljs-keyword"&gt;new&lt;/span&gt; &lt;span class="hljs-type"&gt;ToastSelectionBoxItem&lt;/span&gt;(&lt;span class="hljs-string"&gt;"jahr"&lt;/span&gt;, &lt;br/&gt;    &lt;span class="hljs-string"&gt;"Jahres-Abonnement (152,40 € / 12 Ausgaben)"&lt;/span&gt;)); &lt;br/&gt;  aboInput.Items.Add(&lt;span class="hljs-keyword"&gt;new&lt;/span&gt; &lt;span class="hljs-type"&gt;ToastSelectionBoxItem&lt;/span&gt;(&lt;br/&gt;    &lt;span class="hljs-string"&gt;"student"&lt;/span&gt;, &lt;span class="hljs-string"&gt;"Studenten-Abonnement (89,70 € / &lt;/span&gt;&lt;br/&gt;&lt;span class="hljs-string"&gt;      12 Ausgaben)"&lt;/span&gt;)); &lt;br/&gt;  actions.Inputs.Add(aboInput); &lt;br/&gt;  actions.Buttons.Add(&lt;span class="hljs-keyword"&gt;new&lt;/span&gt; &lt;span class="hljs-type"&gt;ToastButton&lt;/span&gt;(&lt;span class="hljs-string"&gt;"keine Abo"&lt;/span&gt;, &lt;br/&gt;    &lt;span class="hljs-string"&gt;"AboNein"&lt;/span&gt;)); &lt;br/&gt;  actions.Buttons.Add(&lt;span class="hljs-keyword"&gt;new&lt;/span&gt; &lt;span class="hljs-type"&gt;ToastButton&lt;/span&gt;(&lt;span class="hljs-string"&gt;"Abo &lt;/span&gt;&lt;br/&gt;&lt;span class="hljs-string"&gt;    abschließen"&lt;/span&gt;, &lt;span class="hljs-string"&gt;"AboJa"&lt;/span&gt;)); &lt;br/&gt; &lt;br/&gt;  &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; visual = &lt;span class="hljs-keyword"&gt;new&lt;/span&gt; &lt;span class="hljs-type"&gt;ToastVisual&lt;/span&gt;() { BindingGeneric =&lt;br/&gt;    binding }; &lt;br/&gt;  &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; content = &lt;span class="hljs-keyword"&gt;new&lt;/span&gt; &lt;span class="hljs-type"&gt;ToastContent&lt;/span&gt;() { Visual = visual, &lt;br/&gt;    Actions = actions }; &lt;br/&gt; &lt;br/&gt;  &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; xmlDoc = &lt;span class="hljs-keyword"&gt;new&lt;/span&gt; &lt;span class="hljs-type"&gt;XmlDocument&lt;/span&gt;(); &lt;br/&gt;  xmlDoc.LoadXml(content.GetContent()); &lt;br/&gt; &lt;br/&gt;  &lt;span class="hljs-keyword"&gt;var&lt;/span&gt; notification = &lt;span class="hljs-keyword"&gt;new&lt;/span&gt; &lt;span class="hljs-type"&gt;ToastNotification&lt;/span&gt;(xmlDoc); &lt;br/&gt;  notification.Activated += Notification_Activated; &lt;br/&gt;  notification.Dismissed += Notification_Dismissed; &lt;br/&gt;  notification.Failed += Notification_Failed; &lt;br/&gt;  ToastNotificationManager.CreateToastNotifier(&lt;br/&gt;    &lt;span class="hljs-string"&gt;"dotnetpro"&lt;/span&gt;).Show(notification); &lt;br/&gt;}  

Notifications dynamisch erstellt

Das XML-Template, das einer Benachrichtigung zugrunde liegt, kann auch dynamisch per Code erzeugt werden. Dabei hilft die Bibliothek NotificationExtensions.Win10.dll, die als NuGet-Package [4] erhältlich ist. Listing 2 zeigt die Bibliothek im Einsatz und in Bild 2 sehen Sie die daraus erstellte Benachrichtigung.Info-Center Eine Standardbenachrichtigung wird für circa sieben Sekunden am unteren rechten Bildschirmrand angezeigt, bevor sie wieder verschwindet. Anschließend kann man auf diese Benachrichtigung nicht mehr zugreifen.
Damit eine Benachrichtigung im Info-Center erhalten bleibt und erneut angesehen werden kann, muss der Benutzer der Applikation, die die Benachrichtigung initiiert, das Recht erteilen, die Benachrichtigung im Info-Center anzuzeigen. Das kann der Benutzer in den System-Einstellungen unter Benachrichtigungen und Aktionen tun. Hier sind alle Applikationen aufgelistet, die Benachrichtigungen versenden.
Durch einen Mausklick auf die entsprechende Applikation gelangt man in die ­Details. Hier muss, wie in Bild 6 zu sehen, der Schalter Benachrichtigungen im Info-Center anzeigen aktiviert werden. Um dem Be­nutzer diese Arbeit abzunehmen, kann auch ganz einfach ein Registry-Key (Bild 7) unter HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Notifica­tions\Settings\ gesetzt werden, und schon bleibt die Benachrichtigung im Info-Center erhalten und verschwindet dort erst nach explizitem Löschen durch den Benutzer oder wenn die Gültigkeit der Benachrichtigung abgelaufen ist.

Interaktion mit dem Benutzer

Bevor eine Benachrichtigung über den ToastNotifier für die Anzeige an das Betriebssystem übergeben wird, kann man verschiedene Events der Benachrichtigung abonnieren. So ist es möglich zu erfahren, warum eine Benachrichtigung geschlossen und welcher Button angeklickt wurde. Sollte es während der Verarbeitung oder der Anzeige zu Fehlern kommen, kann auch das abgefangen werden. Drei Events stehen dafür zur Verfügung: Activated, Dismissed und Failed.Activated gibt Aufschluss darüber, ob die Benachrichtigung mit der Maus angeklickt beziehungsweise welche Schaltfläche ausgewählt wurde. Dafür wird das Argument, das beim Erstellen der Benachrichtigung angegeben werden kann, in dem Event zurückgegeben. Das Failed-Event gibt eine Exception zurück, die über den Fehlergrund informiert. Das Event Dismissed wird ausgelöst, wenn die Benachrichtigung geschlossen wird. Dafür kommen drei Gründe infrage: Die Benachrichtigung, wird über die Funktion ToastNotifier.Hide() ausgeblendet, der Benutzer schließt die Benachrichtigung, oder der Timeout für die Benachrichtigung ist abgelaufen und sie wird automatisch ausgeblendet.Sie fragen sich jetzt vielleicht, wie die Werte zurückgegeben werden, die in Textfeldern eingegeben oder in Auswahlfeldern markiert wurden? An diese Informationen kommt ­eine Desktop-Anwendung leider nicht heran. Das ist den WinRT- und UWP-Anwendungen vorbehalten.

DualApiPartitionAttribute

Nicht alle Windows-Runtime-Bibliotheken können auch in Desktop-Anwendungen verwendet werden. Ob das möglich ist, darüber gibt das Attribut DualApiPartitionAttribute Aufschluss. Wenn dieses in der Windows-Runtime-Bibliothek enthalten ist, wie es das Beispiel des Geolocators in Bild 8 zeigt, kann sie auch für Desktop-Anwendungen genutzt werden. Diese Information bekommt man in der MSDN-Dokumentation [5] und [6], oder man nutzt das Tool DualApiFinder von Christophe Nasarre [7], das nach Auswahl des Verzeichnisses der Windows-Runtime-Bibliothek(en) alle Klassen auflistet, die das DualApiPartitionAttribute enthalten.
Allerdings fehlen wichtige Klassen wie zum Beispiel User­NotificationChan­gedTrigger aus dem Namensraum Windows.ApplicationModel.Background oder UserNotificationListener aus dem Namensraum Windows.UI.Notifications.Management. Diese beiden Klassen stellen Möglichkeiten bereit, um auf die Texteingabe beziehungsweise die Listenauswahl in Benachrichtigungen zuzugreifen. Bleibt zu hoffen, dass Microsoft hier noch nachbessert und diese Features auch für die Desktop-Anwendungen verfügbar macht.
Projektdateien

Fussnoten

  1. Visual Studio, http://www.dotnetpro.de/SL1708Toast1
  2. Adaptive and interactive toast notifications for Windows 10, http://www.dotnetpro.de/SL1708Toast2
  3. What’s new for Toast notifications and Action Centerin Windows 10 Anniversary Update, http://www.dotnetpro.de/SL1708Toast3
  4. NotificationsExtensions.Win10, http://www.dotnetpro.de/SL1708Toast4
  5. UWP APIs callable from a classic desktop app, http://www.dotnetpro.de/SL1708Toast5
  6. Windows Runtime 8.x APIs for desktop apps, http://www.dotnetpro.de/SL1708Toast6
  7. DualApiFinder or listing winRT types usable by Desktop Apps, http://www.dotnetpro.de/SL1708Toast7

Neueste Beiträge

DWX hakt nach: Wie stellt man Daten besonders lesbar dar?
Dass das Design von Websites maßgeblich für die Lesbarkeit der Inhalte verantwortlich ist, ist klar. Das gleiche gilt aber auch für die Aufbereitung von Daten für Berichte. Worauf besonders zu achten ist, erklären Dr. Ina Humpert und Dr. Julia Norget.
3 Minuten
27. Jun 2025
DWX hakt nach: Wie gestaltet man intuitive User Experiences?
DWX hakt nach: Wie gestaltet man intuitive User Experiences? Intuitive Bedienbarkeit klingt gut – doch wie gelingt sie in der Praxis? UX-Expertin Vicky Pirker verrät auf der Developer Week, worauf es wirklich ankommt. Hier gibt sie vorab einen Einblick in ihre Session.
4 Minuten
27. Jun 2025
„Sieh die KI als Juniorentwickler“
CTO Christian Weyer fühlt sich jung wie schon lange nicht mehr. Woran das liegt und warum er keine Angst um seinen Job hat, erzählt er im dotnetpro-Interview.
15 Minuten
27. Jun 2025
Miscellaneous

Das könnte Dich auch interessieren

UIs für Linux - Bedienoberflächen entwickeln mithilfe von C#, .NET und Avalonia
Es gibt viele UI-Frameworks für .NET, doch nur sehr wenige davon unterstützen Linux. Avalonia schafft als etabliertes Open-Source-Projekt Abhilfe.
16 Minuten
16. Jun 2025
Mythos Motivation - Teamentwicklung
Entwickler bringen Arbeitsfreude und Engagement meist schon von Haus aus mit. Diesen inneren Antrieb zu erhalten sollte für Führungskräfte im Fokus stehen.
13 Minuten
19. Jan 2017
Bausteine guter Architektur - Entwurf und Entwicklung wartbarer Softwaresysteme, Teil 2
Code sauberer gestalten anhand von wenigen Patterns und Grundhaltungen.
6 Minuten
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige