SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

UWPアプリ開発の最前線

急速に進化するUWPアプリのUI
~Windows 10 1809の新コントロール/DataGrid/旧バージョンへのバックポート

UWPアプリ開発の最前線 第9回

DataGridコントロールのカスタマイズ

 Windows Community ToolkitのDataGridは、列定義をカスタマイズしたり、ソート機能を追加したりできます。

列定義をカスタマイズする

 列の定義を次のようにカスタマイズしてみましょう。

  • 特定の列だけを表示する
  • 列ヘッダーの表示をプロパティ名とは変える
  • 特定の列は編集を禁止する

 それには、DataGridコントロールのAutoGenerateColumnsプロパティをFalseに変更した上で、次のコードのように列定義を追加します。ここではDataGridTextColumn(テキストを表示する列)だけを使っていますが、他にDataGridCheckBoxColumn(Nullable<bool>型をバインドするチェックボックス列)とDataGridTemplateColumn(データテンプレートで自由にデザインする列)があります(さらにWindows Community Toolkitバージョン5.0でComboBoxColumnが追加されました)。

DataGridの列をカスタマイズする
<tk:DataGrid x:Name="dataGrid" AutoGenerateColumns="False"
             GridLinesVisibility="All" AlternatingRowBackground="LightCyan">
  <tk:DataGrid.Columns>
    <tk:DataGridTextColumn
      Header="ID" Binding="{Binding 作品ID}" Tag="作品ID" IsReadOnly="True" />
    <tk:DataGridTextColumn
      Header="作品名" Binding="{Binding 作品名}" Tag="作品名" />
    <tk:DataGridTextColumn
      Header="文字遣い" Binding="{Binding 文字遣い種別}" Tag="文字遣い種別" />
    <tk:DataGridTextColumn
      Header="著者" Binding="{Binding 姓名}" Tag="姓名" IsReadOnly="True" />
  </tk:DataGrid.Columns>
</tk:DataGrid>

 DataGridTextColumnのHeaderプロパティが、列ヘッダーに表示される文字列です。IsReadOnlyプロパティをTrueにすると、その列は編集禁止になります。なお、Tagプロパティも追加してありますが、これは次のソート機能で利用するためです。

 これで、次の画像のように表示されるようになりました。

列をカスタマイズしたDataGridコントロール
DataGridの列をカスタマイズした

ソートをサポートする

 DataGridの列ヘッダーをクリックするとSortingイベントが発生します。そのイベントハンドラーでソートを行う処理を書けばよいのです。また、列オブジェクトはSortDirectionプロパティを持っていて、これを設定することで列ヘッダーにソート方向(昇順/降順)を示すマークを表示できます。

XAMLの修正

 次のようにSortingイベントハンドラーを追加します。

DataGridにSortingイベントハンドラーを追加する
<tk:DataGrid x:Name="dataGrid" AutoGenerateColumns="False"
             GridLinesVisibility="All" AlternatingRowBackground="LightCyan"
             Sorting="DataGrid_Sorting"
             >

AdvancedCollectionViewクラス

 さて、ソート処理は、WPFならCollectionViewSourceを使ってサクっとできました。残念ながらUWPのCollectionViewSourceにはソート機能がありません。どうしたものでしょう?

 これまたWindows Community Toolkitに、WPFのCollectionViewと同じように使えるAdvancedCollectionViewクラスがあります(Microsoft.Toolkit.Uwp.UI名前空間)。

 DataGridのItemsSourceプロパティに与えるコレクションを、次のコードのようにAdvancedCollectionViewクラスに変更しておきます。

DataGridに与えるコレクションをAdvancedCollectionViewに変更する
private ObservableCollection<Data.AozoraBunko> _observableCollection;
private AdvancedCollectionView _advancedCollectionView;

private async void LoadAozoraBunkoDataAsync()
{
  IEnumerable<Data.AozoraBunko> list = ……省略(データを取得する)……
  _observableCollection = new ObservableCollection<Data.AozoraBunko>(list);
  _advancedCollectionView
    = new AdvancedCollectionView(_observableCollection, true);
  this.dataGrid.ItemsSource = _advancedCollectionView;
}

Sortingイベントハンドラー

 実際にソートを行う処理を書いていきます。

 まず、どのプロパティをソートに使うかを決めておきます。例えば、[作品名]列ヘッダーをクリックされたときには、[作品名]ではなく、[作品名読み]を使ってソートしたいのです。そこで、次のコードのようなテーブルを定義しておきます。

列ヘッダーのTagとその列のソートに使うプロパティのテーブル
private readonly Dictionary _sortTargets
  = new Dictionary<string, string>
  {
    { "作品ID", "作品ID" },
    { "作品名", "作品名読み" },
    { "文字遣い種別", "文字遣い種別" },
    { "姓名", "姓名読み" },
  };

 ソートするには、「どのプロパティを使って、昇順/降順どちらにソートするのか」を表すSortDescriptionオブジェクトを作って、それをAdvancedCollectionViewのSortDescriptionsプロパティに挿入してやります。SortDescriptionsプロパティには複数のSortDescriptionオブジェクトを設定できて、その際には先頭にあるSortDescriptionオブジェクトが優先されてソートされます。そこで、クリックされた列を優先してソートするために、その列のSortDescriptionオブジェクトをSortDescriptionsプロパティの先頭に挿入します。

 Sortingイベントハンドラーの全体は、次のコードのようになります。

Sortingイベントハンドラー
private async void DataGrid_Sorting(object sender, DataGridColumnEventArgs e)
{
  // ソートに使うプロパティ名(例:[作品名]をクリックされたら[作品名読み]でソート)
  string sortTarget = _sortTargets[e.Column.Tag as string];

  // クリックされた列の、現在のソート方向を取得する
  var currentSortDirection = e.Column.SortDirection;

  // 全ての列ヘッダーのソートマーク(「↑」/「↓」)を消す
  foreach (var c in this.dataGrid.Columns)
    c.SortDirection = null;

  // AdvancedCollectionViewから、以前のSortDescriptionオブジェクトを削除する(もしあれば)
  var oldSort = _advancedCollectionView.SortDescriptions
                  .FirstOrDefault(s => s.PropertyName == sortTarget);
  if (oldSort != null)
    _advancedCollectionView.SortDescriptions.Remove(oldSort);

  if (currentSortDirection == null
      || currentSortDirection == DataGridSortDirection.Descending)
  {
    // 現在、未ソートまたは降順にソートされているなら、
    // 昇順にソート(新しいSortDescriptionオブジェクトを先頭に挿入する)
    _advancedCollectionView.SortDescriptions
      .Insert(0, new SortDescription(sortTarget, SortDirection.Ascending));

    // 列ヘッダーにソートマーク「↑」を付ける
    e.Column.SortDirection = DataGridSortDirection.Ascending;
  }
  else
  {
    // 現在、昇順にソートされているなら、
    // 降順にソート(新しいSortDescriptionオブジェクトを先頭に挿入する)
    _advancedCollectionView.SortDescriptions
      .Insert(0, new SortDescription(sortTarget, SortDirection.Descending));

    // 列ヘッダーにソートマーク「↓」を付ける
    e.Column.SortDirection = DataGridSortDirection.Descending;
  }
}

 これで、次の画像のようにソートができます。この例は、作品名で昇順にソートしてから、作者名で降順にソートしました。

ソート機能を付けたDataGridコントロール
DataGridにソート機能を付けた

行の詳細(Row Details)

 DataGridコントロールは、行ごとにその詳細を表示することもできます。本稿のサンプルコードには実装してありませんが、例えばWindows Community Toolkit Sample Appをご覧ください(次の画像)。

Windows Community Toolkit Sample Appで行を選択するとその詳細が表示される
DataGridの「行の詳細(Row Details)」表示(Windows Community Toolkit Sample App)

 このように、Windows 10 1703(15063)から利用できるDataGridコントロールは、高機能で簡単に使えます。さらに、サンプルコードをリリースビルドして確かめてほしいのですが、表示やソートも十分に高速です。

次のページ
以前のWindows 10へのバックポート

関連リンク

この記事は参考になりましたか?

UWPアプリ開発の最前線連載記事一覧

もっと読む

この記事の著者

biac(ばいあっく)

HONDA R&Dで自動車の設計をやっていた機械屋さんが、技術の進化スピードに魅かれてプログラマーに。以来30年ほど、より良いコードをどうやったら作れるか、模索の人生。わんくま同盟の勉強会(名古屋)で、よく喋ってたりする。2014/10~2019/6 Microsoft MVP (Windows Devel...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/11188 2018/11/20 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー