AdaptiveGridView が行の幅いっぱいに広がらない原因と対策|Windows Community Toolkit(WinUI/UWP)を ItemsRepeater で置き換える

Windows Community Toolkit の AdaptiveGridView を使うと、余白があるのにアイテムが横方向へ伸びず、1 行の幅を使い切らないことがあります。原因と、保守性の高い代替実装(ItemsRepeater)への置き換え手順をまとめます。

目次

発生する症状と、よくある設定例

WinUI / UWP でタイル状の一覧を作るとき、Windows Community Toolkit の AdaptiveGridView は「ウィンドウ幅に応じて列数が増減する」便利なコントロールです。ところが、次のような場面で表示が不自然になることがあります。

  • 列数の計算上、行の右側に十分な余白が残っている
  • それでも 各アイテムが横に伸びず、余白がそのまま空いてしまう
  • StretchContentForSingleRow="True" を指定しても、期待したように「行幅いっぱい」に広がらない

例えば、次のような XAML は多くのプロジェクトで見かけます(DesiredWidth と ItemHeight を指定し、1 行のときは伸ばしたい、という意図)。

<controls:AdaptiveGridView
    DesiredWidth="180"
    ItemHeight="160"
    StretchContentForSingleRow="True"
    ItemsSource="{x:Bind ViewModel.Items, Mode=OneWay}">


<controls:AdaptiveGridView.ItemTemplate>
    <DataTemplate x:DataType="local:MyItem">
        <Grid Padding="10" Background="#FFF7D56B">
            <TextBlock Text="{x:Bind Title}"/>
        </Grid>
    </DataTemplate>
</controls:AdaptiveGridView.ItemTemplate>


しかし実際には「行が 1 行しかない(または見た目上 1 行相当)」状況でも、アイテム幅が固定されたままになり、右側に大きな空白が残ることがあります。

プロパティ期待する効果この問題で起きがちなこと
DesiredWidth最小幅の目安をもとに列数を自動計算列数は合っているのに余白だけ残る
ItemHeightタイルの高さを揃える高さは揃うが幅の問題は解消しない
StretchContentForSingleRow1 行のときに横方向へ伸ばして余白を埋める伸びない/伸びたり伸びなかったりする

結論から言うと「設定ミス」より「コントロール側の挙動」で起きやすい

この現象は、特定のプロパティ設定を間違えたというよりも、AdaptiveGridView 側の想定外挙動として報告されているケースに該当することが多いです。実際に、同様の症状は再現報告があり、既知の issue として扱われています。

つまり、「StretchContentForSingleRow を True にしたのに伸びない」こと自体が、あなたの XAML の書き方だけで説明できない場合があります。

なぜ「行の幅いっぱいに伸びない」ように見えるのか

まず押さえておきたいのは、XAML のレイアウトが 二段階で決まる点です。

  • アイテムの“外枠”(GridViewItem などのコンテナ)が、パネル(WrapGrid 等)によって配置・サイズ決定される
  • DataTemplate 内の見た目は、その外枠の範囲内で Stretch する

そのため、DataTemplate 側で HorizontalAlignment="Stretch" を指定しても、外枠の幅が固定のままであれば、テンプレートはそれ以上広がれません。見た目としては「右側に空白が残る」状態になります。

AdaptiveGridView は内部的に、画面幅・余白・スクロール領域などから「列数」と「アイテム幅」を計算して、GridView の ItemsPanel に反映します。理屈の上では、1 行しかないときに StretchContentForSingleRow が働き、余白を埋める方向に再計算されるはずです。ところが、レイアウト更新のタイミングや計算結果の反映が期待どおりにいかず、古い幅のまま残ってしまうようなケースが発生します。

まず確認したい「テンプレートが伸びない」系の別問題

今回の主題は「コンテナ幅が広がらない」問題ですが、似た見た目で原因が別のケースもあります。以下は “テンプレートが伸びない”ときの定番チェックです。

チェック項目見るポイント効くケース
GridViewItem の ContentAlignmentHorizontalContentAlignment が Stretch かテンプレートが左寄せで縮む問題
DataTemplate の rootroot が StackPanel で幅が固定化していないか中身が自分の幅で止まる問題
固定 Width/MinWidthどこかで Width を固定していないか明示的固定が原因のとき

ただし、ここを整えても「外枠の幅が足りない」状態では余白は残ります。テンプレートの話と、パネルが配る幅の話は分けて考えるのがポイントです。

<Page.Resources>
  <Style TargetType="GridViewItem">
    <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
    <Setter Property="VerticalContentAlignment" Value="Stretch"/>
  </Style>
</Page.Resources>

Windows Community Toolkit の現状:AdaptiveGridView を前提にし続けるのが難しい理由

見た目の問題に加えて、設計面で重要なのが 「コントロールの今後」です。Windows Community Toolkit v8 系ではパッケージ構成が大きく見直され、旧来の Microsoft.Toolkit.Uwp.UI.* や CommunityToolkit.WinUI.UI.* は新しい 8.x 系のパッケージへ誘導される形になりました。

さらに Microsoft Q&A では、旧パッケージ(例:Microsoft.Toolkit.Uwp.UI.Controls)は legacy として deprecated で、実質的にメンテナンス対象外になっている旨が案内されています。挙動が気になっても「修正を待てば解決する」という読みが立てにくいのが、実務上の痛いポイントです。

そして、その移行の過程で AdaptiveGridView は新しいパッケージへ移植されていない(移行対象から外れている)ことが明記されています。代替として ItemsRepeater の UniformGridLayout を使う方針が示されています。

「それでも AdaptiveGridView を移行してほしい」場合は、GitHub 側でディスカッションを立てて要望を集めたり、移植・修正に協力することはできます。ただし、すぐに直る保証はありません。

観点AdaptiveGridView(従来)ItemsRepeater / UniformGridLayout(推奨)
保守状況レガシー扱いで移行されていないWinUI の標準機能として継続改善
余白の制御期待どおりに伸びないことがあるItemsStretch で余白の使い方を明確に指定可能
自由度GridView ベースで柔軟性はあるが挙動に依存レイアウト・仮想化・テンプレートを分離して組み立てやすい
実装コスト既存なら低い置き換え時にテンプレート再設計が必要なことがある

推奨解決策:ItemsRepeater で「余白が残らない」レスポンシブグリッドを作る

ItemsRepeater は、ListView のような “完成品のコントロール” というより、データ駆動で要素を並べるための基盤に近い存在です。アイテムのテンプレートと、並べ方(Layout)を明示して組み立てます。

AdaptiveGridView の「幅に応じて列数が変わる」用途は、UniformGridLayout を使うことで再現できます。UniformGridLayout は MinItemWidth を基準に 1 行あたりの個数を決め、余った幅をどう扱うかを ItemsStretch と ItemsJustification でコントロールできます。

目的おすすめ設定効果
余白を消してタイルを広げるItemsStretch="Fill"未使用スペースを各アイテムの幅に配分
縦横比を保ちつつ広げるItemsStretch="Uniform"幅だけでなく高さも調整(比率維持)
余白は残すが中央寄せにしたいItemsStretch="None" + ItemsJustification="Center"余白は維持しつつ配置だけ整える

実装例:WinUI 3 / UWP で使える “伸びるグリッド”

基本形(スクロール込み)

ItemsRepeater 自体はスクロールを持たないため、一般的には ScrollViewer の中に入れて一覧として使います。タイルの最小幅を MinItemWidth で決め、余白は ItemsStretch="Fill" で吸収します。

<!-- xmlns:muxc="using:Microsoft.UI.Xaml.Controls" -->
<ScrollViewer HorizontalScrollBarVisibility="Disabled"
              VerticalScrollBarVisibility="Auto">

  <muxc:ItemsRepeater ItemsSource="{x:Bind ViewModel.Items, Mode=OneWay}">
    <muxc:ItemsRepeater.Layout>
      <muxc:UniformGridLayout
          MinItemWidth="180"
          MinItemHeight="160"
          MinColumnSpacing="12"
          MinRowSpacing="12"
          ItemsStretch="Fill"/>
    </muxc:ItemsRepeater.Layout>

    <muxc:ItemsRepeater.ItemTemplate>
      <DataTemplate x:DataType="local:MyItem">
        <Border CornerRadius="8"
                Padding="12"
                BorderThickness="1"
                BorderBrush="{ThemeResource SystemControlForegroundBaseLowBrush}">

          <Grid>
            <Grid.RowDefinitions>
              <RowDefinition />
              <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>

            <FontIcon Glyph="" FontSize="22"
                      HorizontalAlignment="Center" VerticalAlignment="Center"/>

            <TextBlock Grid.Row="1"
                       Text="{x:Bind Title}"
                       TextTrimming="CharacterEllipsis"/>
          </Grid>

        </Border>
      </DataTemplate>
    </muxc:ItemsRepeater.ItemTemplate>
  </muxc:ItemsRepeater>

</ScrollViewer>

この形にすると、ウィンドウを広げたときに右側へ残りがちなスペースが アイテム幅に再配分されやすく、「行の幅を使い切る」見た目になります。

クリック(タップ)できるタイルにする

ItemsRepeater は ListView のような選択やクリックの仕組みを自動で付けないため、タイルに “押せる” 挙動が欲しい場合は、テンプレート内に Button を置くのが分かりやすいです。

<DataTemplate x:DataType="local:MyItem">
  <Button Padding="0"
          HorizontalAlignment="Stretch"
          HorizontalContentAlignment="Stretch"
          Command="{x:Bind ViewModel.OpenCommand}"
          CommandParameter="{x:Bind}">

    <Border CornerRadius="8" Padding="12"
            Background="{ThemeResource CardBackgroundFillColorDefaultBrush}">
      <TextBlock Text="{x:Bind Title}" />
    </Border>

  </Button>
</DataTemplate>

「ボタンに見せたくない」場合は、Button のスタイルをフラットにするか、PointerPressed/Released を自前で扱う方法もありますが、まずは Button で体験を固めるのが安全です。

選択状態が必要なら ItemsView も検討する

「GridView 的な選択(SelectedItem / SelectionMode)が欲しい」場合、ItemsRepeater に SelectionModel を組み込む実装もできますが、要件によっては ItemsView のような items view 系コントロールの方が近い場合があります。ItemsView はレイアウトを切り替えつつ選択を保つ設計があり、UniformGridLayout も利用できます。

移行の判断基準:いつ ItemsRepeater へ置き換えるべきか

「すぐ置き換えるべきか」「いったん様子を見るか」は、画面の重要度と今後の改修頻度で決めるのが現実的です。

状況おすすめ理由
新規開発/今後も継続して機能追加する最初から ItemsRepeater(または ItemsView)保守される仕組みに寄せた方がコストが読める
既存画面だが、見た目の崩れが UX に直結する優先度高で置き換え「たまに伸びない」系はテストで捕まえにくい
既存画面で、見た目より機能優先・改修予定が少ない暫定対応+中期で移行手戻りを抑えつつ、将来の詰まりを回避

どうしても AdaptiveGridView を残したい場合の現実的な回避策

「既存の画面が多すぎて、今すぐ ItemsRepeater に寄せられない」ケースもあります。ここでは、長期的におすすめではないものの、現場でよく採られる “つなぎ” を整理します。

再レイアウトを促して当たりを引く(暫定)

ウィンドウのリサイズや画面遷移などのタイミングで、幅が再計算されずに残ってしまう場合があります。再計測を促す目的で、サイズ変更時に InvalidateMeasure() を呼ぶ、ItemsSource を入れ替える、などの方法が候補になります。ただし、UI スレッド負荷やちらつきの原因になりやすいので、恒久策には向きません。

GridView + ItemsWrapGrid で自前計算する(制御はできる)

AdaptiveGridView の “やりたいこと” はシンプルで、「ある最小幅を守りつつ、列数を計算し、各アイテム幅を 幅/列数 にする」です。これを GridView の ItemsPanel に ItemsWrapGrid を置き、SizeChanged で手動計算すると、挙動を完全に把握できます。

<GridView x:Name="MyGrid"
          ItemsSource="{x:Bind ViewModel.Items, Mode=OneWay}"
          SizeChanged="MyGrid_SizeChanged">

  <GridView.ItemsPanel>
    <ItemsPanelTemplate>
      <ItemsWrapGrid />
    </ItemsPanelTemplate>
  </GridView.ItemsPanel>

  <GridView.ItemTemplate>
    <DataTemplate x:DataType="local:MyItem">
      <Border Padding="12" CornerRadius="8">
        <TextBlock Text="{x:Bind Title}"/>
      </Border>
    </DataTemplate>
  </GridView.ItemTemplate>
</GridView>
private const double MinTileWidth = 180;
private const double TileHeight = 160;

private void MyGrid_SizeChanged(object sender, SizeChangedEventArgs e)
{
    if (sender is not GridView gv) return;
    if (gv.ItemsPanelRoot is not ItemsWrapGrid panel) return;

    var width = e.NewSize.Width;
    if (width <= 0) return;

    // 列数を決める(最低 1 列)
    var columns = Math.Max(1, (int)Math.Floor(width / MinTileWidth));

    // 余白を残したくないので、幅を列数で割って均等配分
    panel.ItemWidth = width / columns;
    panel.ItemHeight = TileHeight;
}

この方法のメリットは「挙動が読みやすい」ことです。一方で、AdaptiveGridView のような付加機能(細かな最適化や追加プロパティ)を期待している場合は、自分で補う必要があります。

ソースを取り込んでフォークする(最後の手段)

どうしても AdaptiveGridView の API 形状を維持したい場合は、コントロールのソースを自プロジェクトに取り込み、必要な修正を当てて運用する方法もあります。ただし、これは “自分で面倒を見る” という意味なので、チーム体制とテスト戦略がないと危険です。

GitHub でディスカッション/報告するなら、最小限ここまで用意する

「自分の環境だけの問題ではないか?」を切り分けるためにも、報告は再現性が命です。以下の情報が揃っていると、議論が前に進みやすくなります。

項目例意図
ターゲットUWP / WinUI 3(Windows App SDK)パッケージと挙動が変わるため
Toolkit のパッケージとバージョンCommunityToolkit.WinUI.UI.Controls 7.x など旧系か新系かの判断材料
最小再現 XAMLDataTemplate を単純化したもの要因切り分けの最短ルート
期待結果と実結果「余白を埋めたい」「右に空白が残る」仕様かバグかの判断
ウィンドウ幅の条件どの幅で起きるか、リサイズ手順計算境界(丸め)を特定しやすい

既に同種の issue は存在するため、完全な新規投稿よりも「追加の再現条件」「別環境での再現」「最小コード」など、価値のある追記を意識すると建設的です。

まとめ

  • AdaptiveGridView の「余白があるのにアイテムが行幅いっぱいに伸びない」現象は、設定だけで片付かないケースがある
  • Windows Community Toolkit v8 の流れでは AdaptiveGridView は移行されておらず、将来性を考えると依存し続けるリスクがある
  • 代替としては ItemsRepeater + UniformGridLayout が現実的で、ItemsStretch="Fill" で余白問題を明確に制御できる
  • 既存の制約で置き換えが難しい場合は、GridView + ItemsWrapGrid の自前計算など “読みやすい挙動” に寄せて暫定運用する

参考情報(検索の起点)

  • Microsoft Q&A「Windows Community Toolkit AdaptiveGridView incorrect behavior」(2025-01-24)
  • Microsoft Dev Blogs「Announcing Windows Community Toolkit v8.0」(2023-09-07)
  • GitHub Issue「AdaptiveGridView not adapting to available space #4979」(2024-03-24)
  • Microsoft Learn「ItemsRepeater – Windows apps」(2025-11-24)
  • Microsoft Learn「AdaptiveGridView Class(Microsoft.Toolkit.Uwp.UI.Controls)」
  • Microsoft Learn「Guidelines for items view controls(ItemsView)」

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次