TcxGridのソート

2010/3/8 内容を修正しました。

TcxGridのソートについて。CustomDataSourceを使ったUnbound modeではなく、DataSetを使ったProvider modeでの話です。
Viewについては、DBTableView又はDBBandedTableViewを想定してます。

ViewのDataController.DataModeController.GridModeの値によって処理が変わってきます。
GridModeがFalseの場合は、ソートやフィルタなんかの処理はGrid側で面倒見てくれます。
ただ、全レコードをメモリに読み込んで処理するので、レコード数が少ない場合はこれで良いんですがレコード数が多くなってくるとパフォーマンスに問題が出てきます。(どの位まで大丈夫なのかはあんまり調べてないし、環境にもよると思うのでなんとも言えません。)

GridModeをTrueに設定すると決まったレコード数のみをメモリにロードするようになります。読み込むレコード数は、DataController.DataModeController.GridModeBufferCountで設定します。初期値の0を指定してあると表示されるレコード数から自動的に決定してくれるようです。
この時は、ソートやフィルタの処理は自分でやる必要が出てきます。


ソートの設定は、ViewのOptionsCustomize.ColumnSortingで設定した場合は、列全部がソート可能になります。

列に対して個別に設定する場合は、それぞれの列のOptions.Sortingで設定します。


ソートの許可された列のヘッダをクリックすると、その列に対するソートの設定をします。

列ヘッダをクリックするときにShiftを押しながらクリックすると現在のソートに追加して複数列のソートを設定する事が出来ます。

// カラムのソート順データを指定した順番に並び替える比較関数
function SortOrdersSort(List: TStringList; Index1, Index2: Integer): Integer;
begin
  if Integer(List.Objects[Index1]) = Integer(List.Objects[Index2]) then
    Result := 0
  else if Integer(List.Objects[Index1]) < Integer(List.Objects[Index2]) then
    Result := -1
  else
    Result := 1;
end;

上のコードはStringListのObjectsにInt値をキャストで無理矢理設定して、その値を使ってStringListをソートする処理です。下記のコードで、列をソートするときの設定された順番通りにORDER BYを組み立てるために利用します。

そして下記が、クリックで設定されたソート順に基づいてクエリのORDER BYの中身を組み立てる処理です。

// ORDER BYの中身を組み立てる。
function GetOrder: String;
const
  CSORDERTYPE: Array[TcxDataSortOrder] of String=('', ' ASC',' DESC');
var
  Idx: Integer;
  Orders: TStringList;
begin
  Result := '';
  // StringListを利用して複数列にソート設定された場合の順番設定をします。
  Orders := TStringList.Create;
  for Idx := 0 to cxView.ColumnCount - 1 do
  begin
    // まずは、全列に対してSortOrderがsoNone以外の列をStringListに追加します。
    // この時、StringListに追加する文字列をデータベースのフィールド名だけで無く、SortOrderの設定に従って
    // フィールド名の後ろに昇順/降順を示す ASC/DESC を追加しておきます
    // また、列のSortIndexにソート設定された順番が入ってるのでこれをStringList.Objectsに入れておきます。
    if cxView.Columns[Idx].SortOrder <> soNone then
    begin
      Orders.AddObject(cxView.Columns[Idx].DataBinding.FieldName + CSORDERTYPE[cxView.Columns[Idx].SortOrder], 
        TObject(cxView.Columns[Idx].SortIndex));
    end;
  end;

  if Orders.Count > 0 then
  begin
    // 指定された順番でソート条件を構築する
    Orders.CustomSort(SortOrdersSort);
    // ソートされたデータを順番に ','で区切ってつなげて文字列を返します。
    Result := ' ORDER BY ' + Orders.Strings[0];
    for Idx := 1 to Orders.Count - 1 do
      Result := Result + ',' + Orders.Strings[Idx];
  end;
  FreeAndNil(Orders);
end;