maui-collectionview について
.NET MAUI の CollectionView で、スクロール可能なデータリストやグリッドを表示するための技能です。バインディング、更新、段階的な読み込みに加え、UI やパフォーマンス上の問題を避けるレイアウトとスレッドの扱いを説明します。
主な機能
- 01ObservableCollection によるデータバインド
- 02ViewCell を使わない項目テンプレート
- 03祖先バインドを使った SwipeView
- 04プル更新と段階的な読み込み
- 05仮想化に適したレイアウト選択
- 06サイズ計測と UI スレッド更新の改善
活用シーン
- 01変化するデータをリストやグリッドで表示
- 02スワイプコマンドとプル更新を追加
- 03スクロールに応じて項目を追加読み込み
- 04空の項目やスクロールの遅さを調査
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ davidortinau/ maui-skills --skill maui-collectionviewインストール後、Claude Code で/maui-collectionviewを入力して読み込まれたか確認します。
同梱ファイルevals/evals.jsonreferences/collectionview-api.md
詳細
CollectionView – .NET MAUI
スクロール可能なデータのリストやグリッドを表示するには、CollectionView を使用します。
ListView に代わるもので、パフォーマンスが向上し、レイアウトの柔軟性が高く、ViewCell が不要です。
基本的なパターン
基本設定
<CollectionView ItemsSource="{Binding Items}">
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="models:Item">
<HorizontalStackLayout Padding="8" Spacing="8">
<Image Source="{Binding Icon}" WidthRequest="40" HeightRequest="40" />
<Label Text="{Binding Name}" VerticalOptions="Center" />
</HorizontalStackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
ItemsSourceをObservableCollection<T>にバインドすると、項目の追加や削除が UI に反映されます。- 各項目テンプレートのルートには
LayoutまたはViewを指定する必要があります。ViewCellは絶対に使用しないでください。 - コンパイル済みバインディングを使用するには、
DataTemplateに必ずx:DataTypeを設定してください。
SwipeView — DataTemplate 内からのバインディング
DataTemplate 内のコマンドから ViewModel に直接アクセスすることはできません。RelativeSource AncestorType を使用します。
<SwipeItem Text="Delete"
BackgroundColor="Red"
Command="{Binding Source={RelativeSource AncestorType={x:Type viewmodels:MainViewModel}}, Path=DeleteCommand}"
CommandParameter="{Binding}" />
引っ張って更新
CollectionView を RefreshView でラップします。完了したら IsRefreshing を false に戻します。
<RefreshView IsRefreshing="{Binding IsRefreshing}"
Command="{Binding RefreshCommand}">
<CollectionView ItemsSource="{Binding Items}" />
</RefreshView>
段階的な読み込み(無限スクロール)
<CollectionView ItemsSource="{Binding Items}"
RemainingItemsThreshold="5"
RemainingItemsThresholdReachedCommand="{Binding LoadMoreCommand}" />
⚠️ StackLayout ベースの ItemsLayout と併用しないでください。仮想化に対応していないため、しきい値到達イベントが無限に発生します。必ず
LinearItemsLayoutまたはGridItemsLayoutを使用してください。
パフォーマンスのヒント
- 項目のサイズが均一な場合は
MeasureFirstItemを使用してください。既定のMeasureAllItemsより大幅に高速です。<LinearItemsLayout Orientation="Vertical" ItemSizingStrategy="MeasureFirstItem" /> List<T>ではなく、必ずObservableCollection<T>を使用してください。Listを差し替えると、すべてが再描画されます。- コレクションは UI スレッドで更新してください。
MainThread.BeginInvokeOnMainThread(() => Items.Add(item))を使用します。
よくある注意点
| 問題 | 対処法 |
|---|---|
| 項目を変更しても UI が更新されない | List<T> ではなく、ObservableCollection<T> を使用します。 |
| アプリがクラッシュする、または項目が空白になる | ViewCell は絶対に使用しないでください。テンプレートのルートには Grid、StackLayout、または任意の View を使用します。 |
| 項目が消える、またはレイアウトが崩れる | ItemsSource とコレクションは必ず UI スレッドで更新します(MainThread.BeginInvokeOnMainThread)。 |
| 段階的な読み込みが止まらない | レイアウトに StackLayout を使用せず、LinearItemsLayout または GridItemsLayout を使用します。 |
| EmptyView が正しく表示されない | カスタムの空状態ビューを ContentView でラップします。 |
| スクロールのパフォーマンスが低い | 項目のサイズが均一な場合は、サイズ設定方法に MeasureFirstItem を使用します。 |
| 選択状態が表示されない | 項目テンプレートのルート要素に VisualState Name="Selected" を追加します。 |
| SwipeView のコマンドでバインディングエラーが発生する | 項目テンプレート内から ViewModel にアクセスするには、RelativeSource AncestorType を使用します。 |
コメント
Markdown 対応