LoginSignup
6
2

More than 3 years have passed since last update.

ソース ジェネレーターをWPFで使う場合の注意点

Last updated at Posted at 2021-04-11

概要

C# 9.0のソースジェネレーターの実例としてよく挙げられるのが、INotifyPropertyChangedです。
そこで実際にWPFに組み込もうとしたところ、結構苦労したので、その注意点を説明します。

組み込むソースジェネレータ

INotifyPropertyChangedを実装するソースジェネレータは 公式サンプルもありますが、より多機能な@okazukiさんのプロジェクトを組み込みます。

テストアプリ

題材とするテストアプリです。ViewModelは上記の記事のままです。ソースジェネレータを組み込んでいないので、まだビルドすることはできません。

ViewModel

public partial class MainWindowViewModel
{
    [AutoNotify("Xxxx")]
    private string _firstName;

    [AutoNotify]
    private string _lastName;

    [AutoNotify]
    public string FullName => $"{Xxxx} {LastName}";
}

View

<Window
   x:Class="MvvmGenerator.WpfTests.MainWindow"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:local="clr-namespace:MvvmGenerator.WpfTests"
   Width="300" Height="250">
   <Window.DataContext>
      <local:MainWindowViewModel />
   </Window.DataContext>
   <StackPanel>
      <TextBox Text="{Binding Xxxx}" />
      <TextBox Text="{Binding LastName}" />
      <TextBlock Text="{Binding FullName}" />
   </StackPanel>
</Window>

ソースジェネレータプロジェクト

コンソールアプリケーションではプロジェクト参照でも動きますが、現時点(2021/04/11)ではWPFでは動きません。

nugetパッケージ化

まず、ソースジェネレータプロジェクトをnugetパッケージ化する必要があります。
通常のパッケージとは違うので、いくつか変更するところがあります。

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <LangVersion>preview</LangVersion>
    <Nullable>enable</Nullable>
    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
    <IncludeBuildOutput>false</IncludeBuildOutput>
    <IncludeSymbols>false</IncludeSymbols>
    <DevelopmentDependency>true</DevelopmentDependency>
    <SuppressDependenciesWhenPacking>true</SuppressDependenciesWhenPacking>    <TargetsForTfmSpecificContentInPackage>$(TargetsForTfmSpecificContentInPackage);_AddAnalyzersToOutput</TargetsForTfmSpecificContentInPackage>
    <Version>1.3.0</Version>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.8.0-3.final" PrivateAssets="all" />
    <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.0" PrivateAssets="all" />
  </ItemGroup>

  <Target Name="_AddAnalyzersToOutput">
    <ItemGroup>
      <TfmSpecificPackageFile Include="$(OutputPath)\MvvmGenerator.dll" PackagePath="analyzers/dotnet/cs" />
    </ItemGroup>
  </Target>
</Project>
プロパティ名 説明
IncludeBuildOutput false パッケージに通常のdll組み込みはしない
IncludeSymbols false パッケージにシンボルファイル(.pdb)は含めない
SuppressDependenciesWhenPacking true プロジェクトで使用しているパッケージの依存関係は含めない
DevelopmentDependency true 開発用のパッケージとして認識されるようにする。
TargetsForTfmSpecificContentInPackage $(Targ... パッケージに組み込むカスタムターゲットを指定する

TargetsForTfmSpecificContentInPackageから下記のカスタムターゲットを指定します。

<Target Name="_AddAnalyzersToOutput">
  <ItemGroup>
    <TfmSpecificPackageFile Include="$(OutputPath)\MvvmGenerator.dll" PackagePath="analyzers/dotnet/cs" />
  </ItemGroup>
</Target>

.csprojファイルの編集後ビルドして、.nupkgファイルを作成します。

作成したnupkgファイルの中を見てみると、通常のnupkgファイルとは異なった構成になっているのが分かります。

image-20210411163613090.png

ローカルでパッケージ配布

作成したパッケージはnuget.orgを使用してもいいですが、自分が簡単に使うだけなら、ローカルフォルダに置いてnugetレポジトリとして、VisualStudioに登録することで使えるようになります。

詳しいやり方は以下を参照してください。

WPFプロジェクト

.csproj編集

作成したnugetパッケージをWPFプロジェクトに追加します。
ここでも.csprojファイルの修正が必要です。

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net5.0-windows</TargetFramework>
    <UseWPF>true</UseWPF>
   <IncludePackageReferencesDuringMarkupCompilation>true</IncludePackageReferencesDuringMarkupCompilation>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="MvvmGenerator" Version="1.3.0">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
  </ItemGroup>
</Project>

<IncludePackageReferencesDuringMarkupCompilation>trueに設定します。この長いプロパティは最近追加されたもののようで、まだMicrosoft Docsにも含まれていません。

動作確認

この状態でビルドして動作させます。

2つのTextBoxに入力された内容が、下のTextBlockに反映されることから、INotifyPropertyChangedが正しく実装されていることが分かります。

image-20210411172220272.png

参考

https://github.com/ufcpp/ValueChangedGenerator/
https://zenn.dev/naminodarie/articles/32973a36fcbe99

ソースコード

今回の完全なソースコードをGithubにおいておきます。okazukiさんの記事のレポジトリをフォークしたものです。
https://github.com/soi013/MvvmGenerator

環境

VisualStudio 2019 Version 16.9.3
.NET 5
C# 9.0

謝辞

WPFで組み込もうとしたところ、うまく動かなかったので、@okazukiさんに助けてもらいました。ありがとうございました。

6
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
2