[C# / WPF] Windows で アカウントに設定された画像を取得して表示する (Windows.System.User.GetPropertyAsync → BitmapImage)

### 概要

* .NET 6.0 な WPF アプリで、User アカウントに設定された画像を取得して、XAMLで表示する。
*  画像の取得は、WinRT な Windows.System.User.GetPropertyAsync で行う。
*  GetPropertyAsync で取得した IRandomAccessStreamReference を WPF の BitmapImage に変換して表示する。
*  サンプルアプリケーションは[こちら](https://github.com/lifework/WPF_UserPicture)。

### ユーザ情報の取得

* [UWPでユーザー名を取得する - かずきのBlog@hatena](https://blog.okazuki.jp/entry/2016/03/04/160555) にあるように、ログインしているユーザー情報は、Windows.System.User で取得します。
  * Msix Packaging プロジェクトを作成して、Package.appxmanifest で、&lt;uap:Capability Name="userAccountInformation"/&gt; しておきます。
* Windows.System.User は、Windows.System の namespace 配下の WinRT な API なので、WPF で利用するには、下記の記事にあるように、NuGet の Microsoft.Windows.SDK.Contracts パッケージをインストールします。
  * [.NET のプロジェクトから WinRT API を呼ぶのが凄く簡単になってます - かずきのBlog@hatena](https://blog.okazuki.jp/entry/2019/05/09/115020) 
  * [[C#] デスクトップアプリ (WPF) から手軽にWinRT APIを活用しよう - Qiita](https://qiita.com/everylittle/items/62ce313fe09883c6da5f)

### IRandomAccessStreamReference を BitmapImage に変換して表示する

[User.GetPictureAsync](https://learn.microsoft.com/en-us/uwp/api/windows.system.user.getpictureasync?view=winrt-22621) の See also で紹介されている、[Windows-universal-samples/Samples/UserInfo/](https://github.com/microsoft/Windows-universal-samples/tree/main/Samples/UserInfo) では、下記のようなコードで BitmapImage に変換していますが、この場合(UWP)のBitmapImage は、[Windows.UI.Xaml.Media.Imaging.BitmapImage](https://learn.microsoft.com/en-us/uwp/api/windows.ui.xaml.media.imaging.bitmapimage?view=winrt-22621) で、WPF の [System.Windows.Media.Imaging.BitmapImage](https://learn.microsoft.com/en-us/dotnet/api/system.windows.media.imaging.bitmapimage?view=windowsdesktop-6.0) では、BitmapImage.SetSource が存在せず、WPFおいてそのままでは使えません。

```C#
IRandomAccessStreamReference streamReference = await user.GetPictureAsync(UserPictureSize.Size64x64);
if (streamReference != null)
{
    IRandomAccessStream stream = await streamReference.OpenReadAsync();
    BitmapImage bitmapImage = new BitmapImage();
    bitmapImage.SetSource(stream);
    ProfileImage.Source = bitmapImage;
}
```

そこで、[C# converting UWP BitmapImage to WPF BitmapImage](https://stackoverflow.com/questions/50596735/c-sharp-converting-uwp-bitmapimage-to-wpf-bitmapimage) で回答されているように、Stream に変換してから BitmapImage.StreamSource に設定することで、WPF で表示できるようになります。

```C#
var user = (await User.FindAllAsync(UserType.LocalUser, UserAuthenticationStatus.LocallyAuthenticated)).FirstOrDefault();

// C# converting UWP BitmapImage to WPF BitmapImage
// https://stackoverflow.com/questions/50596735/c-sharp-converting-uwp-bitmapimage-to-wpf-bitmapimage
IRandomAccessStreamReference streamReference = await user.GetPictureAsync(UserPictureSize.Size208x208);
if (streamReference != null)
{
    var bitmap = new BitmapImage();
    using var randomAccessStream = await streamReference.OpenReadAsync();
    using var stream = randomAccessStream.AsStream();

    bitmap.BeginInit();
    bitmap.CacheOption = BitmapCacheOption.OnLoad;
    bitmap.StreamSource = stream;
    bitmap.EndInit();
    UserPicture.Value = bitmap;
}
```

## サンプルコード

詳細は、[サンプルアプリケーション](https://github.com/lifework/WPF_UserPicture) を見てください。

実行すると下記の画像のようにログインしているユーザーのプロフィール画像が表示されます。

![スクリーンショット 2022-10-12 002759.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2709043/5c878111-42d3-646f-3dbc-1e9449643333.png)