At work we have a component called a "ClientdatasetGrid", which allows the user to sort the records of the grid by clicking on one or multiple column-titles.
I have made a component for work also, a descendant from TEdit, which I call TDBFilterEdit.
once you assign a DataSet or DBGrid to it, it creates an OnFilterRecord event for the DataSet and after you stop changing the text that Event is executed.
the problem arises whenever the Dataset is already filtered and the user sorts the grid.
the grid-component adds IndexDefs to the Clientdataset by first deleteing the current IndexDef, Updating, Adding the new Index and updating again.
whenever an index is deleted or added my OnFilterRecord event is triggered. I mitigated this by disableing controls and NIL-ing the OnFilterRecord event from inside the grid until the new index is added.
cds.DisableControls();
try
extProc:=nil;
if (TMethod(cds.OnFilterRecord).Code<>nil) and (TMethod(cds.OnFilterRecord).Data<>nil) then
begin
TMethod(extProc):=TMethod(cds.OnFilterRecord);
cds.OnFilterRecord:=nil;
end;
...
... //<-- Delete Index & create new Index
...
finally
cds.OnFilterRecord:=extProc;
cds.EnableControls();
end;
Once the Event is assigned again, it is immeadeately called and is iterating through all X records even though the user may only see 5.
Now I am searching for a way to see if a record is already filtered out so I can skip it inside my filter-method if the text hasn't changed.
Edit: Since a MVCE has been demanded I'll post a short version of my OnFilterRecord procedure.
- the following procedure is executed everytime the component hasn't recieved an input for 1 second
- fStringtypes and fTimeTypes are both a set of TFieldType
- fStringTypes:=[ftString,ftMemo,ftFMTMemo,ftFixedChar,ftWideString];
- fTimeTypes:=[ftDate,ftTime,ftDateTime,ftTimeStamp];
after the procedure is completely finished the timer is disabled and controls are enabled again.
procedure TDBEditFilter.FilterRecords(DataSet:TDataSet; var Accept:Boolean); var ... begin //initiliaztion// s:=FilterText; //Filtertext=User Input into the TDBEditFilters Textfield TestFloat:=0; Accept:=False; ///////////////// for i:=0 to fDBGrid.Columns.Count-1 do //for all DBGrid-Columns begin if fDataSet.FieldByName(fDBGrid.Columns[i].FieldName).DataType in fStringTypes then begin Strvalue:=fDataSet.FieldByName(fDBGrid.Columns[i].FieldName).AsString; Accept:=AnsiContainsText(Strvalue,s); //<--to ignore Upper/lowercase end else if fDataSet.FieldByName(fDBGrid.Columns[i].FieldName).DataType in fTimeTypes then begin StrValue:=DateTimeToStr(fDataSet.FieldByName(fDBGrid.Columns[i].FieldName).As DateTime,Local_Form_Settings); Accept:=Pos(StrValue,s)<>0; end else if fDataSet.FieldByName(fDBGrid.Columns[i].FieldName).DataType=ftBlob then begin //ignore Blob end else //whatever fieldtype is left must be a numeric Field-type like integer or float begin if TryStrToFloat(s,TestFloat)=True then begin Accept:=(TestFloat=fDataSet.FieldByName(fDBGrid.Columns[i].FieldName).AsFloat); end; end; if Accept=True then break; //stop checking this record and check next record end; end;