.NET MAUIのXAMLでDesignInstanceを利用する

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 のコンパイルは既定で有効です。

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 が利用できるようになって欲しいです。切実に。

執筆担当者プロフィール
中谷 大造

中谷 大造(日本ビジネスシステムズ株式会社)

情報システム部の中谷です。社内用スクラッチアプリの開発をしています。

担当記事一覧