TcxCustomDataSource

DevExpressのTcxGridてグリッドコントロール、データベースのデータ一覧とかで良く使ってます。
今回は、データベースじゃなく自分で定義したデータとTcxGridを連携する時に使うTcxCustomDataSourceの使い方をメモ。

とりあえずデータクラスを定義

  TUserData = class
  private
    FId: Integer;
    FName: String;
  public
    property Id: Integer read FId write FId;
    property Name: String read FName write FName;
  end;

Gridと連携する上で、実装しないといけないメソッドは GetRecordCount、GetValue、SetValue、InsertRecord、AppendRecord、DeleteRecordの6つ。
まあ、グリッド上ではデータ表示するだけで編集とか一切無しって場合はGetRecordCount、GetValueの二つで良いかと。編集する場合は、SetValueが必要ですね。
後のメソッド、InsertRecord、AppendRecord、DeleteRecordの3つはViewのOptionsDataのInserting、Appending、DeletingをTrueに設定した時に実装する必要有り。
実装すると以下のような感じに

  TUserDataSource = class(TcxCustomDataSource)
  private
    FItems: TObjectList<TUserData>;
  protected
    function AppendRecord: TcxDataRecordHandle; override;
    function InsertRecord(ARecordHandle: TcxDataRecordHandle): TcxDataRecordHandle;
        override;
    procedure DeleteRecord(ARecordHandle: TcxDataRecordHandle); override;
    function GetRecordCount: Integer; override;
    function GetRecordHandle(ARecordIndex: Integer): TcxDataRecordHandle; override;
    function GetValue(ARecordHandle: TcxDataRecordHandle; AItemHandle:
        TcxDataItemHandle): Variant; override;
    procedure SetValue(ARecordHandle: TcxDataRecordHandle; AItemHandle:
        TcxDataItemHandle; const AValue: Variant); override;
  public
    constructor Create;
    destructor Destroy; override;
  end;

function TUserDataSource.AppendRecord: TcxDataRecordHandle;
var
  Im: TUserData;
begin
  Im := TUserData.Create;
  FItems.Add(Im);
  Result := TcxDataRecordHandle(Im);
  DataChanged;
end;

constructor TUserDataSource.Create;
begin
  FItems := TObjectList<TUserData>.Create;
end;

procedure TUserDataSource.DeleteRecord(ARecordHandle: TcxDataRecordHandle);
var
  Idx: Integer;
begin
  Idx := FItems.IndexOf(ARecordHandle);
  if Idx <> -1 then
    FItems.Delete(Idx);
  DataChanged;
end;

destructor TUserDataSource.Destroy;
begin
  FreeAndNil(FItems);
  inherited;
end;

function TUserDataSource.GetRecordCount: Integer;
begin
  Result := FItems.Count;
end;

function TUserDataSource.GetRecordHandle(
  ARecordIndex: Integer): TcxDataRecordHandle;
begin
  Result := TcxDataRecordHandle(FItems.Items[ARecordIndex]);
end;

function TUserDataSource.GetValue(ARecordHandle: TcxDataRecordHandle;
    AItemHandle: TcxDataItemHandle): Variant;
var
  ColumnId: Integer;
  Im: TUserData;
begin
  ColumnId := GetDefaultItemID(Integer(AItemHandle));
  Im := TUserData(ARecordHandle);

  case ColumnId of
  0: Result := Im.Id;
  1: Result := Im.Name;
  end;
end;

function TUserDataSource.InsertRecord(ARecordHandle: TcxDataRecordHandle):
    TcxDataRecordHandle;
var
  Idx: Integer;
  Im: TUserData;
begin
  Idx := FItems.IndexOf(ARecordHandle);

  Im := Nil;
  if Idx <> -1 then
  begin
    Im := TUserData.Create;
    FItems.Insert(Idx, Im);
  end;
  Result := Im;
  DataChanged;
end;

procedure TUserDataSource.SetValue(ARecordHandle: TcxDataRecordHandle;
    AItemHandle: TcxDataItemHandle; const AValue: Variant);
var
  ColumnId: Integer;
  Im: TUserData;
begin
  ColumnId := GetDefaultItemID(Integer(AItemHandle));
  Im := TUserData(ARecordHandle);

  case ColumnId of
  0: Im.Id := AValue;
  1: Im.Name := AValue;
  end;
end;

InsertRecord、AppendRecord、DeleteRecordの3つを実装した時は、リストのデータを更新した後、DataChangedを実行しないとデータの更新が反映されないので忘れないように注意かなぁ。