WPF や Xamarin の XAML では DataContext に対して DesignInstance の設定を行い、 XAML 記述時にデータバインドする ViewModel の IntelliSense を有効にすることができました。筆者が MAUI を触ってみたところ全く利用できなくなってしまっていたため、暫定の解決方法を記しておきます。
試した環境
要素 | バージョン |
---|---|
Visual Studio | 17.3.6 |
.NET SDK | 6.0.402 |
やりたかったこと
XAML は MVVM (Model-View-ViewModel) パターンの View にあたる要素で、 View と ViewModel は XAML 上に定義するデータバインドで結合されています。ただ XAML は一種の XML = 文字列 ですので、うっかりたいぽして ViewModel とのデータバインドに失敗してしまうこともあります。このような凡ミスを防ぐ効果がある、と筆者が思っているのが以下のデザイン支援の設定です。
<!-- Before --> <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="MauiBindingSampleApp.MainPage"> <Label Text="{Binding LabelText}" /> </ContentPage> <!-- After --> <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:MauiBindingSampleApp" mc:Ignorable="d" x:Class="MauiBindingSampleApp.MainPage" d:DataContext="{d:DesignInstance local:MainPageViewModel, IsDesignTimeCreatable=True}"> <Label Text="{Binding LabelText}" /> </ContentPage>
XAML の名前空間に xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
を追加して DataContext にデザイナー用の ViewModel を流し込むことで、デザイナー上でのダミー表示や XAML データバインドの ViewModel に対する IntelliSense が有効になります。
ただしこの機能を Xamarin.Forms で利用するにはアセンブリに対して属性を付与する一工夫が必要でした。
[assembly: XamlCompilation(XamlCompilationOptions.Compile)]
そして Xamarin.Forms の後継である MAUI では、実行時にエラーが発生してしまいこの一工夫すら動作しなくなりました。そもそも MAUI では XAML のコンパイルは既定で有効です。
暫定的な解決策
Xamarin.Forms および MAUI ではデザイン時に使用すべき名前空間が変更されています。この名前空間を使用すれば実行時エラーは発生しません。
対象 | 名前空間 |
---|---|
Xamarin.Forms | http://xamarin.com/schemas/2014/forms/design |
MAUI | http://schemas.microsoft.com/dotnet/2021/maui/design |
この名前空間を利用する場合、デザイナー用の ViewModel を指定するには d:ContentPage.BindingContext
を指定します。
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:d="http://schemas.microsoft.com/dotnet/2021/maui/design" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:MauiBindingSampleApp" mc:Ignorable="d" x:Class="MauiBindingSampleApp.MainPage"> <!-- デザイナー用の指定 --> <d:ContentPage.BindingContext> <local:MainPageViewModel /> </d:ContentPage.BindingContext> <Label Text="{Binding LabelText}" /> </ContentPage>
ちなみにこの記述方法、実行には影響が無いのですが、空のコンストラクターを持つ ViewModel でないと XLS0507
エラーとなります。 DI 使用を前提とする場合空のコンストラクターの ViewModel を用意することは難しいですので、中々に度しがたいですね。
そこで更に一工夫、 ViewModel側にデザイナー用のインスタンスを渡す static フィールドを追加します。
using Microsoft.Extensions.Logging; namespace MauiBindingSampleApp; public class MainPageViewModel { // デザイン時の用のインスタンスを返すstaticフィールドを作成 #if DEBUG public static MainPageViewModel DesignInstance = new(null!); #endif private readonly ILogger<MainPageViewModel> _logger; public string LabelText { get; set; } = "Hello!"; public MainPageViewModel(ILogger<MainPageViewModel> logger) { _logger = logger; } }
そして XAML もこのフィールドを使用するように書き換えます。
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:d="http://schemas.microsoft.com/dotnet/2021/maui/design" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:MauiBindingSampleApp" mc:Ignorable="d" x:Class="MauiBindingSampleApp.MainPage"> <!-- デザイナー用の指定 --> <d:ContentPage.BindingContext> <Binding Source="{x:Static local:MainPageViewModel.DesignInstance}" /> </d:ContentPage.BindingContext> <Label Text="{Binding LabelText}" /> </ContentPage>
筆者環境ではこの実装でエラー出力無く動作しました。
おわりに
MAUI では DesignInstance を全く利用できなかったため、代案の紹介でした。
将来 MAUI の XAML デザイナーが登場した際にコンストラクターに null
を渡しているため実装次第ではエラーとなってしまう可能性もありますが、現時点ではどうしようもないのかなと感じています。 MAUI の仕様が変更されて WPF の DesignInstance が利用できるようになって欲しいです。切実に。