Windows10にはアクションセンターがあります。 メールやSlackなどのメッセージ受信をぴろーんと通知してくるあれです。 これをWPFアプリから使いたいと思いました。
何年か前にもWPFアプリで通知機能を使いたいなと思ったのですが、そのときはなにやらいろいろと大変そうだったのでやめた記憶がうっすらとあります。
それが、最近になって割と簡単に使えるようになったとかずきさんのブログで知って、改めてやってみたくなった次第です。
WPFアプリからアクションセンターに通知を出す手順については以下のページに詳しく書かれていて、その手順どおりにやっただけです。 ほんとありがとうございます。
UWPからは簡単
さて、このアクションセンターへの通知の表示を行うにはWinRT APIを使う必要があります。 UWPアプリからは非常に簡単に使うことができます。
例えば、空のUWPアプリを作成してボタンを配置し、コードビハインドのClickイベントハンドラに以下のコードを貼り付けて実行してみましょう。 このコードは上記のサイトに掲載されているサンプルコードです。
string title = "The current time is"; string timeString = $"{DateTime.Now:HH:mm:ss}"; string thomasImage = "https://www.thomasclaudiushuber.com/thomas.jpg"; string toastXmlString = $@"<toast><visual> <binding template='ToastGeneric'> <text>{title}</text> <text>{timeString}</text> <image src='{thomasImage}'/> </binding> </visual></toast>"; var xmlDoc = new XmlDocument(); xmlDoc.LoadXml(toastXmlString); var toastNotification = new ToastNotification(xmlDoc); var toastNotifier = ToastNotificationManager.CreateToastNotifier(); toastNotifier.Show(toastNotification);
必要なusingは以下のとおりです。
using System; using System.Windows; using Windows.Data.Xml.Dom; using Windows.UI.Notifications;
ボタンを押すと、ぴろーん。 イケメンの写真とともに現在時刻が通知されます。

WPFだとひと手間必要(本題)
前述のサイトではWPF .NET Frameworkを使っていますが、せっかくなのでWPF Coreでやってみます。
まずはWPF Coreのプロジェクトを作成します。

次にMicrosoft.Windows.SDK.ContractsをNugetからインストール。
このあたりの手順についてはかずきさんのブログが詳しいかなと思います。

ツール > オプションを選択してオプションウィンドウを表示します。
設定項目の中からNugetパッケージマネージャーを選択します。
パッケージの管理で、規定のパッケージ管理形式にPackageReferenceを選択します。

ここまででWPFアプリからWinRT APIを呼び出すことができるようになりました。
このWPFアプリにもボタンを一つ配置してClickイベントハンドラに前述のサンプルコードを貼り付けましょう。
必要なusingを追加してビルドしましょう。
通ったはずです。
では実行してボタンを押すと、ぴろーんといくかと思いきや以下のエラーが。

このエラーがでるのは前述の英語サイトでは予定どおりということで以下のように説明されていました。
The problem here is that your WPF application doesn’t have a package identity. A UWP app has a package identity, and it is installed in Windows 10 with that identity. But a WPF app doesn’t have such an identity, so let’s create one.
ざっくりいうと、
原因は、WPFはアプリはパッケージ識別子がないため。UWPアプリはパッケージ識別子があって、アプリと識別子はWindows10に一緒にインストールされる。でも、WPFアプリはその識別子がない。だから作っちゃう。
ということです。
これについてはかずきさんの以下の記事のまとめでも書かれているとおり、「通知」は識別子が割り当てられないと使えないAPIということでした。
識別子がない問題を解決する
ではこの識別子の問題をどうやって解決するかというと、Windows アプリケーションパッケージプロジェクトを使ってWPFアプリをストアアプリ(UWPアプリ)としてパッケージ化してやります。
デスクトップアプリのストアアプリ化(?)の手順については公式サイトが詳しいです。
「Windows アプリケーションパッケージプロジェクト」の追加
ではまず、ソリューションにプロジェクトをもう一つ追加します。

プロジェクトテンプレートとして、Windows アプリケーションパッケージプロジェクトを選択します。プロジェクトタイプをUWPで絞り込むと見つけやすいかと思います。
名前は適当に。

新しく追加したプロジェクトのアプリケーションのコンテキストメニューから参照の追加を選択します。

WPF Coreプロジェクトを参照に追加します。

こんなエラーが。

TargetPlatformVersionが合わない。なるほど。
確かに、先程インストールしたMicrosoft.Windows.SDK.Contractsのバージョンは最新(プレビュー)の10.0.18362.0でした。
それに対してWindows アプリケーションパッケージプロジェクトの作成時に選択したバージョンは10.0.17763.0でした。
というわけで、NugetでMicrosoft.Windows.SDK.Contractsのバージョンを10.0.17763.0にします。

これで準備完了です。
実行
それでは実行します。 ウィンドウが表示されて、ボタンを押すと。
ぴろーん。

イケメンが現在時刻を教えてくれます。
おわりに
設定ファイルを手動で変更したり、必要なファイルを手動で配置したりといったことなしに、Nugetでのパッケージ追加、設定変更、参照追加など全ての作業をVisual Studioで完了でき、とても「簡単」にWPFアプリからアクションセンターに通知を表示できたと思います。
Windows アプリケーションパッケージプロジェクトでWPFアプリを包むところがトリッキーといえばトリッキーですが、やってることはプロジェクトの参照だけなので難しいことはありません。