neputa note

.NET MAUI CollectionViewでBindingの値がnullになる問題を解決する方法

初稿:

- 4 min read -

img of .NET MAUI CollectionViewでBindingの値がnullになる問題を解決する方法

概要

.NET MAUIのCollectionViewを使用しているときに、“Binding .”の値がnullになる問題に直面した。

状況としては、CollectionViewの”SwipeItemView”でスワイプしたときに実行するCommandのパラメータをBindingで指定しているのだが、値がnullになってしまうというもの。

原因と解決策を備忘録としてまとめる。

環境

  • .NET 8.0 (net8.0-android)
  • CommunityToolkit.Maui 9.1.1
  • CommunityToolkit.Mvvm 8.3.2

問題の詳細

以下のようなCollectionViewを使用している。

MainView.xaml
<ContentPage
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:local="clr-namespace:CollectionViewDemos.ViewModels"
    x:Class="CollectionViewDemos.Views"
    x:DataType="local:HslColorViewModel"
    Title="MainVIew">

    <!-- 省略 -->

    <CollectionView
        x:Name="collectionView"
        ItemsSource="{Binding Items}"
        SelectionMode="None">
        <CollectionView.ItemTemplate>
            <DataTemplate>
                <SwipeView>
                    <SwipeView.RightItems>
                        <SwipeItems>
                            <SwipeItem
                                Text="Delete"
                                Command="{Binding Source={x:Reference collectionView}, Path=, Path=BindingContext.DeleteCommand}"
                                CommandParameter="{Binding .}" />
                        </SwipeItems>
                    </SwipeView.RightItems>
                    <Label Text="{Binding Name}" />
                </SwipeView>
            </DataTemplate>
        </CollectionView.ItemTemplate>
    </CollectionView>

    <!-- 省略 -->

</ContentPage>

問題が起きているのは、上記のハイライト部分。

XAMLでコンパイル済みのバインドを使用しているが、エラーや警告も出ていない。

また、デバッグ時には問題なく動作する。

ところが、Releaseビルドで実行すると”Binding .の値がnull”になってしまう。

原因

ちゃんと公式に書いてあった。

Bindings in a DataTemplate are interpreted in the context of the object being templated. Therefore, when using compiled bindings in a DataTemplate, the DataTemplate needs to declare the type of its data object using the x:DataType attribute. Failure to do this could result in the DataTemplate inheriting an incorrect x:DataType from its parent scope: DataTemplateのバインディングは、テンプレート化されるオブジェクトのコンテキストで解釈されます。 したがって、DataTemplateでコンパイルされたバインディングを使用する場合、DataTemplateはx:DataType属性を使用してデータオブジェクトの型を宣言する必要があります。これを行わないと、DataTemplateがその親スコープから正しくないx:DataTypeを継承してしまう可能性があります Compiled bindings - .NET MAUI | Microsoft Learnより引用

解決策

つまり、こうしなさいということ。

MainView.xaml
<ContentPage
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:models="clr-namespace:CollectionViewDemos.ViewModels"
    xmlns:local="clr-namespace:CollectionViewDemos.Models"
    x:Class="CollectionViewDemos.Views"
    x:DataType="models:HslColorViewModel"
    Title="MainVIew">

    <!-- 省略 -->

    <CollectionView
        x:Name="collectionView"
        ItemsSource="{Binding Items}"
        SelectionMode="None">
        <CollectionView.ItemTemplate>
            <DataTemplate>
            <DataTemplate x:DataType="local:Item">
                <SwipeView>
                    <SwipeView.RightItems>
                        <SwipeItems>
                            <SwipeItem
                                Text="Delete"
                                Command="{Binding Source={x:Reference collectionView}, Path=, Path=BindingContext.DeleteCommand}"
                                CommandParameter="{Binding .}" />
                        </SwipeItems>
                    </SwipeView.RightItems>
                    <Label Text="{Binding Name}" />
                </SwipeView>
            </DataTemplate>
        </CollectionView.ItemTemplate>
    </CollectionView>

    <!-- 省略 -->

</ContentPage>

ここでは、仮に”Item”というクラスを使用しているとする。

Item.cs

namespace CollectionViewDemos.Models;

public class Item
{
    public string Name { get; set; }
}

“x:DataType”で型を指定することで、Bindingのコンテキストが正しく解決されるようになる。

まとめ

GitHub Copilot先生の助けを借りながら取り組んでいたが、なかなか解決できずにいた。

最終的には、公式ドキュメントを見て解決できた。

新しい技術を使うときは、ドキュメントをしっかり読むこと大事。

以上。

目次