1

I have a cxGrid where I apply a filter to select certain records. When that is done I want to be able to update a field/column in the grid to mark each record that is to be used for the next operation. I haven't been able to figure this out

Maybe I haven't been specific enough when describing my problem. I have the cxGrid where I have applied a filter selecting some records. What I then need to do is to click a columnheader and then have a field called fldselected set to True for these records.

OZ8HP
  • 1,443
  • 4
  • 31
  • 61
  • Ime, the best way to do this is to include an "unbound" check column in the grid - it avoids the overhead of doing an .Edit/.Post to save the selection state in a data field of the dataset. Devex have examples of how to do this. – MartynA Jun 08 '15 at 16:53
  • I don't want to use an unbound column as the marked data is to be used in another operation as soon as the form is closed. So it has to be bound to a field in the dataset. – OZ8HP Jun 09 '15 at 16:17
  • No it doesn't necessarily have to be bound - just the selection state of individual rows in the dataset and their IDs need to be persisted for the next operation. Anyway, if you want to do it your way, then just do it - respond to a click in the grid by updating whatever field you're interested in. But there are potential traps for the unwary, e.g. you should make sure the dataset isn't indexed on that field. – MartynA Jun 09 '15 at 16:22
  • Well, you've had answers now about how to do it with an unbound column and a bound one; do neither of these answer your q? – MartynA Jun 11 '15 at 08:12
  • As far as I can test none of them do - as the updated question says I don't want to mark each selection. I want to click the columnheader and have every selected record updated. I can't get any of the sample code here to do that - maybe it is just me. – OZ8HP Jun 11 '15 at 08:45
  • Ah, that's a bit different to what I'd understood you were asking for. I've replaced my previous answer by one which hopefully now does what you want. Please confirm (or clarify). – MartynA Jun 11 '15 at 12:40

2 Answers2

2

What your updated q is asking for is straightforward and as usual with Devex stuff, it's all in the OLH as long as you can find your way into it.

A way to find which rows currently match the filter is to use the

cxGrid1DBTableView1.DataController.FilteredRecordIndex[]

property. You can then find that record in the dataset to process it in some way using

cxGrid1DBTableView1.DataController.LocateByKey().

Update: The original version of this answer assumed that the dataset had an integer ID field. As the OP has said he uses GUIDs instead, I've upddated it accordingly.

Assuming the TClientDataSet CDS1 has fields Guid : TGuidField, Name : TStringfield, size 32 and Selected : TBooleanField and is connected to a cxDBTableView, with filtering enabled, of a TcxGrid.

  • Make sure the cxGrid1DBTableView1.DataController.KeyFieldNames is set to 'Guid'.

  • Add a regular TDBGrid to the form and point it at the same datasource as the TcxGrid. The point of this is to make it easy to verify that the code is working as required.

  • Add the code below to the unit, and point cxDBTableView1's OnColumnHeaderClick at the handler cxGrid1DBTableView1ColumnHeaderClick, and the form's OnCreate at the FormCreate.

Compiler & run

Code:

procedure TForm1.cxGrid1DBTableView1ColumnHeaderClick(Sender: TcxGridTableView;
    AColumn: TcxGridColumn);
begin
  if AColumn = cxGrid1DBTableView1Name then
    ProcessFilteredRecords;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  AGuid : TGuid;
  i : Integer;
  lResult : Longint;
begin
  CDS1.IndexFieldNames := 'Name';
  CDS1.CreateDataSet;

  for i:= 0 to 6 do begin
    lResult := SysUtils.CreateGUID(AGuid);
    CDS1.Insert;
    CDS1.FieldByName('Name').AsString := Chr(Ord('A') + i);
    CDS1.FieldByName('Guid').AsString := GuidToString(AGuid);
    CDS1.FieldByName('Selected').AsBoolean := False;
    CDS1.Post;
  end;

  CDS1.First;
end;

procedure TForm1.ProcessFilteredRecords;
var
  V : Variant;
  i,
  Index: Integer;
  BM : TBookMark;
begin

  BM := CDS1.GetBookMark;
  CDS1.DisableControls;
  try
    for i := 0 to cxGrid1DBTableView1.DataController.FilteredRecordCount - 1 do begin
      Index := cxGrid1DBTableView1.DataController.FilteredRecordIndex[i];
      // Next, get the GUID value of the row
      V := cxGrid1DBTableView1.DataController.Values[Index, 0];
      if cxGrid1DBTableView1.DataController.LocateByKey(V) then begin
        CDS1.Edit;
        CDS1.FieldByName('Selected').AsBoolean := True;
        CDS1.Post;
      end;
    end;
  finally
    CDS1.EnableControls;
    CDS1.GotoBookmark(BM);
    CDS1.FreeBookmark(BM);
  end;
end;
MartynA
  • 30,454
  • 4
  • 32
  • 73
  • Looks more promising but my data doesn't have an integer ID - it has a stringfield (a GUID9 so I will have to alter it a bit and due to time it won't be before tomorrow at earliest - but I will return. – OZ8HP Jun 11 '15 at 15:40
  • Ok, I've updated my answer to use GUIDs instead of an integer ID field. Tested with filters on the Name field, such as like Name >= 'D' – MartynA Jun 11 '15 at 18:12
  • Thank you very much - now I have got a working solution – OZ8HP Jun 12 '15 at 17:28
  • I have found a strange thing in this - the record that is active in the cxGrid is not processed. And it doesn't matter if the active record is first, last or somewhere between. – OZ8HP Jun 14 '15 at 11:57
  • I will have a look at this later. But meanwhile, I think it might be better to revert your q to its previous version and describe the specific problem you are having now in a new question. After all, Sam M went to the trouble of trying to answer the question you originally asked, but now his answer doesn't seem to have anything to do with what you're now asking. Later ... – MartynA Jun 14 '15 at 12:32
  • OK - I have removed the solution and started a new question with my observations on this strange behavior that I have observed – OZ8HP Jun 15 '15 at 08:25
1

Check out https://www.devexpress.com/Support/Center/Question/Details/A1095, the article from Dev Express. Don't let the fact that the article is 11 years old fool you. The same technique still applies. And you can set this up either in code or in the grid editor.

  1. Create the column in the grid editor.
  2. Set the columns DataBinding.ValueType to Boolean (if that's what you want the checkbox to represent)
  3. Set the Data Controller's KeyFieldNames property. Very important! I have spent hours scratching my head with an non-functioning unbound column only to find that the KeyFieldNames wasn't set.

An unbound column can be referenced in your next operation using the DataController Records or Values array, depending on how you set that up. Because it is unbound you cannot reference it through the underlying DataSet though.

Sam M
  • 4,136
  • 4
  • 29
  • 42