.NET Core 3と2以下の混在下でWPF/WinFormを有効にする
また何年振りかという更新です。
課題
.NET Core 3.0から、WPFとWindows Formsがサポートされました。WPFを使う場合のcsprojファイルの基本形は以下です。
(<UseWPF>
を <UseWindowsForms>
と置き換えればWindows Forms向けになります。)
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop"> <PropertyGroup> <OutputType>Library</OutputType> <TargetFramework>netcoreapp3.1</TargetFramework> <UseWPF>true</UseWPF> </PropertyGroup> </Project>
本記事は、ここで何らかの理由で TargetFrameworks
に netcoreapp3.1
以外を入れたくなった場合の話です。
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop"> <PropertyGroup> <OutputType>Library</OutputType> <TargetFrameworks>netcoreapp3.1;netcoreapp2.1</TargetFrameworks> <UseWPF>true</UseWPF> </PropertyGroup> </Project>
netcoreapp2.1ではWPFは使えません。警告が出るだけなので無視を決め込んでも良いかもしれませんが、何とかしてみましょう。あくまでこういうことができるという話として。
解決法
以下を参考にします。ひょっとするともう少し簡単に書けるのかもしれませんが。 github.com
<Project> <Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" Condition="'$(TargetFramework)' != 'netcoreapp3.1'" /> <Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk.WindowsDesktop" Condition="'$(TargetFramework)' == 'netcoreapp3.1'" /> <PropertyGroup> <TargetFrameworks>netcoreapp3.1;netcoreapp2.1</TargetFrameworks> <OutputType>Library</OutputType> </PropertyGroup> <PropertyGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'"> <UseWPF>true</UseWPF> </PropertyGroup> <Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" Condition="'$(TargetFramework)' != 'netcoreapp3.1'" /> <Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk.WindowsDesktop" Condition="'$(TargetFramework)' == 'netcoreapp3.1'" /> </Project>
Microsoft.NET.Sdk.WindowsDesktop
と UseWPF
について、netcoreapp3.1
のときだけ有効にします。
マルチプラットフォーム対応
WPF・Windows Formsに対応と言っても、現在のところWindows限定なのは変わりません。このcsprojをLinuxに持って行ってビルドすると失敗します。
そこまで考慮したい場合は以下のようにします。OSによる分岐は以下のページが参考になります。
<Project> <Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" Condition="'$(OS)' != 'Windows_NT' Or '$(TargetFramework)' != 'netcoreapp3.1'" /> <Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk.WindowsDesktop" Condition="'$(OS)' == 'Windows_NT' And '$(TargetFramework)' == 'netcoreapp3.1'" /> <PropertyGroup> <TargetFrameworks>netcoreapp3.1;netcoreapp2.1</TargetFrameworks> <OutputType>Library</OutputType> </PropertyGroup> <PropertyGroup Condition="'$(OS)' == 'Windows_NT' And '$(TargetFramework)' == 'netcoreapp3.1'"> <UseWPF>true</UseWPF> </PropertyGroup> <PropertyGroup Condition="'$(OS)' == 'Windows_NT'"> <DefineConstants>$(DefineConstants);WINDOWS;</DefineConstants> </PropertyGroup> <Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" Condition="'$(OS)' != 'Windows_NT' Or '$(TargetFramework)' != 'netcoreapp3.1'" /> <Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk.WindowsDesktop" Condition="'$(OS)' == 'Windows_NT' And '$(TargetFramework)' == 'netcoreapp3.1'" /> </Project>
上記では、WINDOWS
というコンパイラ定数を定義しています。csprojさえ分岐して乗り切ればよいわけではなく、実際にはコードでも分岐が必要になるためです。using System.Windows.Media;
等といった箇所でエラーが出てきます。
Hoge.cs(4,22): error CS0234: The type or namespace name 'Media' does not exist in the namespace 'System.Windows' (are you missing an assembly reference?) [/foo/bar/baz.csproj]
コンパイラ定数を使って、WPFの利用箇所をまるごと無効にするような格好になるでしょう。
#if WINDOWS && NETCOREAPP3_1 using System; using System.Windows; using System.Windows.Media; using System.Windows.Media.Imaging; ... (以下略) ... #endif