Route gh-aw workflow design/create/debug/upgrade requests to the right prompts.
日本語の概要は準備中です。原文の説明を表示しています。
Guidance for implementing CollectionView in .NET MAUI apps — data display, layouts (list & grid), selection, grouping, scrolling, empty views, templates, incremental loading, swipe actions, and pull-to-refresh. USE FOR: "CollectionView", "list view", "grid layout", "data template", "item template", "grouping", "pull to refresh", "incremental loading", "swipe actions", "empty view", "selection mode", "scroll to item", displaying scrollable data, replacing ListView. DO NOT USE FOR: simple static layouts without scrollable data (use Grid or StackLayout), map pin lists (use Microsoft.Maui.Controls.Maps), table-based data entry forms, non-MAUI list controls, CarouselView or BindableLayout questions, platform-specific handler or renderer customization, diagnosing CollectionView bugs in the MAUI framework itself, or general MVVM/binding questions that merely happen to mention a list (use maui-data-binding).
インストール方法を見るインストールする前に、エージェントに与えられる指示の中身を確認できます。
CollectionView is the primary control for displaying scrollable lists and grids of data in .NET MAUI. It replaces ListView with better performance, flexible layouts, and no ViewCell requirement.
Grid or StackLayout directlyMicrosoft.Maui.Controls.Maps NuGet packageBindableLayout on a StackLayoutThis skill is a reference you consult, not a checklist you apply. Most requests need one or two sections from it. Pulling in the rest makes the answer worse.
Stop conditions — do NOT act when:
CollectionView. CarouselView, BindableLayout, and
ListView-in-maintenance code have different rules. Do not rewrite ListView
code the user did not ask about — but if they ask which control to use, or are
migrating from Xamarin.Forms, recommend CollectionView (see
Migrating from ListView).maui-data-binding, maui-dependency-injection, or
maui-shell-navigation.The API sections below are a reference, not a checklist — offer them only when relevant. Four rules are non-negotiable, because violating them produces code that does not work or silently loses compile-time checking:
ViewCell as a DataTemplate root in CollectionView.ObservableCollection<T> when the list mutates after first render.x:DataType on every DataTemplate (and on the page root) for compiled bindings.Everything else — sizing strategy, snap points, header/footer, empty views — is optional and should be offered only when it addresses the user's actual problem.
ObservableCollection<T>) bound to ItemsSourceDataTemplate defining how each item rendersA complete, copy-pasteable page. Two things are load-bearing: the xmlns:models
declaration that every x:DataType="models:Item" in this skill assumes, and the
root x:DataType — without it the outer ItemsSource binding is not compiled:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:models="clr-namespace:MyApp.Models"
xmlns:vm="clr-namespace:MyApp.ViewModels"
x:DataType="vm:ItemsViewModel"
x:Class="MyApp.ItemsPage">
<ContentPage.BindingContext>
<vm:ItemsViewModel />
</ContentPage.BindingContext>
<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>
</ContentPage>
Later snippets show only the CollectionView element. When you hand a snippet to a
user, include the matching xmlns: declaration for any prefix it uses, or the XAML
will not compile.
The inline <ContentPage.BindingContext> above keeps the example self-contained. In
an app that uses dependency injection, register the ViewModel instead and assign it
through constructor injection (BindingContext = vm;) — see the
maui-dependency-injection skill.
Key rules:
ItemsSource to an ObservableCollection<T> so the UI updates on add/remove.Layout or View — never use ViewCell.x:DataType on DataTemplate for compiled bindings.Set ItemsLayout to control arrangement. Default is VerticalList.
| Layout | XAML value |
|---|---|
| Vertical list | VerticalList (default) |
| Horizontal list | HorizontalList |
| Vertical grid | GridItemsLayout with Orientation="Vertical" |
| Horizontal grid | GridItemsLayout with Orientation="Horizontal" |
<CollectionView ItemsSource="{Binding Items}">
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical"
Span="2"
VerticalItemSpacing="8"
HorizontalItemSpacing="8" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="models:Item">
<Border Padding="8" StrokeThickness="0">
<VerticalStackLayout>
<Image Source="{Binding Image}" HeightRequest="120" Aspect="AspectFill" />
<Label Text="{Binding Name}" FontAttributes="Bold" />
</VerticalStackLayout>
</Border>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<CollectionView ItemsSource="{Binding Items}"
ItemsLayout="HorizontalList" />
| Mode | Property to bind | Binding mode |
|---|---|---|
None | — | — |
Single | SelectedItem | TwoWay |
Multiple | SelectedItems | OneWay |
<CollectionView ItemsSource="{Binding Items}"
SelectionMode="Single"
SelectedItem="{Binding CurrentItem, Mode=TwoWay}"
SelectionChangedCommand="{Binding ItemSelectedCommand}" />
For Multiple selection, bind SelectedItems (type IList<object>):
<CollectionView SelectionMode="Multiple"
SelectedItems="{Binding ChosenItems, Mode=OneWay}" />
Highlight selected items using VisualStateManager:
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="models:Item">
<Grid Padding="8">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="CommonStates">
<VisualState Name="Normal">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Transparent" />
</VisualState.Setters>
</VisualState>
<VisualState Name="Selected">
<VisualState.Setters>
<Setter Property="BackgroundColor"
Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource PrimaryDark}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Label Text="{Binding Name}" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
List<T>:public class AnimalGroup : List<Animal>
{
public string Name { get; }
public AnimalGroup(string name, List<Animal> animals) : base(animals)
{
Name = name;
}
}
ObservableCollection<AnimalGroup> and set IsGrouped="True":<CollectionView ItemsSource="{Binding AnimalGroups}"
IsGrouped="True">
<CollectionView.GroupHeaderTemplate>
<DataTemplate x:DataType="models:AnimalGroup">
<Label Text="{Binding Name}"
FontAttributes="Bold"
BackgroundColor="{StaticResource Gray100}"
Padding="8" />
</DataTemplate>
</CollectionView.GroupHeaderTemplate>
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="models:Animal">
<Label Text="{Binding Name}" Padding="16,4" />
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
Wrap CollectionView in a RefreshView. Set IsRefreshing back to false when done:
<RefreshView IsRefreshing="{Binding IsRefreshing}"
Command="{Binding RefreshCommand}">
<CollectionView ItemsSource="{Binding Items}" />
</RefreshView>
<CollectionView ItemsSource="{Binding Items}"
RemainingItemsThreshold="5"
RemainingItemsThresholdReachedCommand="{Binding LoadMoreCommand}" />
⚠️ Do NOT use with non-virtualizing layouts.
LinearItemsLayoutandGridItemsLayoutsupport virtualization. UsingBindableLayouton aStackLayoutas an alternative toCollectionViewhas no virtualization, which triggers infinite threshold-reached events.
Commands inside a DataTemplate can't directly reach your ViewModel. Use RelativeSource AncestorType:
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="models:Item">
<SwipeView>
<SwipeView.RightItems>
<SwipeItems>
<SwipeItem Text="Delete"
BackgroundColor="Red"
Command="{Binding BindingContext.DeleteCommand, Source={RelativeSource AncestorType={x:Type ContentPage}}}"
CommandParameter="{Binding}" />
</SwipeItems>
</SwipeView.RightItems>
<Grid Padding="8">
<Label Text="{Binding Name}" />
</Grid>
</SwipeView>
</DataTemplate>
</CollectionView.ItemTemplate>
Shown when ItemsSource is empty or null.
<CollectionView ItemsSource="{Binding SearchResults}"
EmptyView="No items found." />
For a custom empty view, wrap in ContentView:
<CollectionView ItemsSource="{Binding SearchResults}">
<CollectionView.EmptyView>
<ContentView>
<VerticalStackLayout HorizontalOptions="Center" VerticalOptions="Center">
<Image Source="empty_state.png" WidthRequest="120" />
<Label Text="Nothing here yet" HorizontalTextAlignment="Center" />
</VerticalStackLayout>
</ContentView>
</CollectionView.EmptyView>
</CollectionView>
<CollectionView ItemsSource="{Binding Items}">
<CollectionView.Header>
<Label Text="Header" FontAttributes="Bold" Padding="8" />
</CollectionView.Header>
<CollectionView.Footer>
<Label Text="Footer" FontAttributes="Italic" Padding="8" />
</CollectionView.Footer>
</CollectionView>
Use HeaderTemplate / FooterTemplate when headers or footers are data-bound.
Programmatically scroll by index or item:
// Scroll to index
collectionView.ScrollTo(index: 10, position: ScrollToPosition.Center, animate: true);
// Scroll to item
collectionView.ScrollTo(item: myItem, position: ScrollToPosition.MakeVisible, animate: true);
| ScrollToPosition | Behavior |
|---|---|
MakeVisible | Scrolls just enough to make the item visible |
Start | Scrolls item to the start of the viewport |
Center | Scrolls item to the center of the viewport |
End | Scrolls item to the end of the viewport |
<CollectionView.ItemsLayout>
<LinearItemsLayout Orientation="Horizontal"
SnapPointsType="MandatorySingle"
SnapPointsAlignment="Center" />
</CollectionView.ItemsLayout>
SnapPointsType: None, Mandatory, MandatorySingleSnapPointsAlignment: Start, Center, EndListView still compiles, but as of .NET 10 it is marked [Obsolete]
("ListView is deprecated. Please use CollectionView instead."). It is not
obsolete on .NET 9 and earlier, so check the project's target framework before
describing it as deprecated. If the user asks
which control to use, or is migrating from Xamarin.Forms, recommend
CollectionView — it is faster, needs no ViewCell, and supports flexible
layouts. What to avoid is silently rewriting ListView code the user did not ask
you to touch.
ListView | CollectionView equivalent |
|---|---|
ViewCell template root | Any View/Layout root — ViewCell is not supported |
ItemSelected event | SelectionChanged event, or SelectionChangedCommand |
ItemTapped event | A TapGestureRecognizer in the item template — SelectionChanged only fires when the selection changes, so it will not re-fire on tapping the already-selected item |
IsPullToRefreshEnabled + Refreshing | Wrap the CollectionView in a RefreshView |
IsGroupingEnabled | IsGrouped |
HasUnevenRows="True" | Default ItemSizingStrategy="MeasureAllItems" |
RowHeight (fixed height) | Set the height in the item template. MeasureFirstItem only reuses the first item's measured size — it is not an explicit row height |
SeparatorVisibility / SeparatorColor | No equivalent — draw a BoxView/Border in the item template |
The missing separator API is the most common migration surprise: CollectionView
has no built-in separators, so add one to the template yourself.
Apply these only when the user reports a performance problem or explicitly asks about performance — they are not a default checklist.
MeasureFirstItem for uniform item sizes — significantly faster than the default
MeasureAllItems, which measures every item individually. Set it on the CollectionView
itself (it is declared on StructuredItemsView), not on LinearItemsLayout /
GridItemsLayout:
<CollectionView ItemsSource="{Binding Items}"
ItemSizingStrategy="MeasureFirstItem">
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="models:Item">
<Grid Padding="8" ColumnDefinitions="44,*" ColumnSpacing="8">
<Image WidthRequest="44" HeightRequest="44" />
<Label Grid.Column="1" Text="{Binding Name}" VerticalOptions="Center" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
When MeasureFirstItem is the wrong choice — keep the default MeasureAllItems if:
DataTemplateSelector returns different templates — the first item won't represent
the others.MeasureAllItems instead.ObservableCollection<T> when the list mutates after first render. It implements
INotifyCollectionChanged, so in-place Add/Remove/Insert update the UI incrementally.
A List<T> is fine for a list that never changes after it is bound. Note that replacing
ItemsSource re-renders everything regardless of the collection type — so mutate the bound
collection in place rather than reassigning it.MainThread.BeginInvokeOnMainThread(() => Items.Add(item)).| Issue | Fix |
|---|---|
| UI doesn't update when items change | Use ObservableCollection<T>, not List<T>. |
| App crashes or blank items | Never use ViewCell — use Grid, StackLayout, or any View as template root. |
| Items disappear or layout breaks | Always update ItemsSource and the collection on the UI thread (MainThread.BeginInvokeOnMainThread). |
| Incremental loading fires endlessly | Don't use StackLayout as layout; use LinearItemsLayout or GridItemsLayout. |
| EmptyView doesn't render correctly | Wrap custom empty views in ContentView. |
| Poor scroll performance | Use MeasureFirstItem sizing strategy for uniform item sizes. |
ItemSizingStrategy doesn't compile | It is declared on StructuredItemsView — set it on <CollectionView>, not on <LinearItemsLayout> / <GridItemsLayout>. |
| Items clipped or stretched | MeasureFirstItem assumes uniform item size. Use the default MeasureAllItems for variable-height items. |
| Selected state not visible | Add VisualState Name="Selected" to the item template root element. |
| Binding errors in SwipeView commands | Use RelativeSource AncestorType to reach the ViewModel from inside the item template. |
Before returning CollectionView markup you wrote or edited, confirm:
DataTemplate root is a View/Layout — not ViewCell.DataTemplate declares x:DataType for compiled bindings.ItemsSource is bound to ObservableCollection<T> if the list mutates.ItemSizingStrategy (if used) is on <CollectionView>, not on the layout.Multiple selection binds SelectedItems; Single binds SelectedItem (TwoWay).RefreshView.IsRefreshing is set back to false when the refresh completes.まだレビューはありません。使ってみた感想をお寄せください。
概要と使いどころ
Route gh-aw workflow design/create/debug/upgrade requests to the right prompts.
日本語の概要は準備中です。原文の説明を表示しています。
Use a repo-root `.editorconfig` to configure free .NET analyzer and style rules. Use when a .NET repo needs rule severity, code-style options, section layout, or analyzer ownership made explicit. USE FOR: the repo needs a root .editorconfig; analyzer severity and style ownership are unclear; the team wants one source of truth for rule configuration. DO NOT USE FOR: choosing analyzers with no config change; formatting-only execution with no config ownership question. INVOKES: inspect the repository context, edit targeted files, and run relevant build, test, lint, or validation commands when changes are made.
日本語の概要は準備中です。原文の説明を表示しています。
Scans .NET code for ~50 performance anti-patterns across async, memory, strings, collections, LINQ, regex, serialization, and I/O with tiered severity classification. Use when analyzing .NET code for optimization opportunities, reviewing hot paths, or auditing allocation-heavy patterns.
日本語の概要は準備中です。原文の説明を表示しています。
Symbolicate the .NET runtime frames in an Android tombstone file. Extracts BuildIds and PC offsets from the native backtrace, downloads debug symbols from the Microsoft symbol server, and runs llvm-symbolizer to produce function names with source file and line numbers. USE FOR triaging a .NET MAUI or Mono Android app crash from a tombstone, resolving native backtrace frames in libmonosgen-2.0.so or libcoreclr.so to .NET runtime source code, or investigating SIGABRT, SIGSEGV, or other native signals originating from the .NET runtime on Android. DO NOT USE FOR pure Java/Kotlin crashes, managed .NET exceptions that are already captured in logcat, or iOS crash logs. INVOKES Symbolicate-Tombstone.ps1 script, llvm-symbolizer, Microsoft symbol server.
日本語の概要は準備中です。原文の説明を表示しています。
Symbolicate .NET runtime frames in Apple platform .ips crash logs (iOS, tvOS, Mac Catalyst, macOS). Extracts UUIDs and addresses from the native backtrace, locates dSYM debug symbols, and runs atos to produce function names with source file and line numbers. Automatically downloads .dwarf symbols from the Microsoft symbol server using Mach-O UUIDs. USE FOR triaging a .NET MAUI or Mono app crash from an .ips file on any Apple platform, resolving native backtrace frames in libcoreclr or libmonosgen-2.0 to .NET runtime source code, retrieving .ips crash logs from a connected iOS device or iPhone, or investigating EXC_CRASH, EXC_BAD_ACCESS, SIGABRT, or SIGSEGV originating from the .NET runtime. DO NOT USE FOR pure Swift/Objective-C crashes with no .NET components, or Android tombstone files. INVOKES Symbolicate-Crash.ps1 script, atos, dwarfdump, idevicecrashreport.
日本語の概要は準備中です。原文の説明を表示しています。
Design or review .NET solution architecture across modular monoliths, clean architecture, vertical slices, microservices, DDD, CQRS, and cloud-native boundaries without over-engineering. USE FOR: .NET architecture choices; layer and domain boundary review; service decomposition; clean architecture, vertical slice, DDD, CQRS, and modular monolith decisions. DO NOT USE FOR: unrelated stacks; generic tasks that do not need this specific guidance. INVOKES: inspect the repository context, edit targeted files, and run relevant build, test, lint, or validation commands when changes are made.
日本語の概要は準備中です。原文の説明を表示しています。