title: Delphi: check if Record of DataSet is visible or filtered
body: <p>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.</p>
  
  <p>I have made a component for work also, a descendant from TEdit, which I call TDBFilterEdit.</p>
  
  <p>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.</p>
  
  <p>the problem arises whenever the Dataset is already filtered and the user sorts the grid.</p>
  
  <p>the grid-component adds IndexDefs to the Clientdataset by first deleteing the current IndexDef, Updating, Adding the new Index and updating again.</p>
  
  <p>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.</p>
  
  <pre><code>cds.DisableControls();
  try
    extProc:=nil;  
    if (TMethod(cds.OnFilterRecord).Code&lt;&gt;nil) and (TMethod(cds.OnFilterRecord).Data&lt;&gt;nil) then 
    begin
      TMethod(extProc):=TMethod(cds.OnFilterRecord);
      cds.OnFilterRecord:=nil;
    end; 
    ...
    ...  //&lt;-- Delete Index &amp; create new Index
    ...
  finally
    cds.OnFilterRecord:=extProc;
    cds.EnableControls();  
  end;
  </code></pre>
  
  <p>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.</p>
  
  <p>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.</p>
  
  <hr>
  
  <p>Edit: Since a MVCE has been demanded I'll post a short version of my OnFilterRecord procedure.</p>
  
  <ul>
  <li>the following procedure is executed everytime the component hasn't recieved an input for 1 second</li>
  <li>fStringtypes and fTimeTypes are both a set of TFieldType</li>
  <li>fStringTypes:=[ftString,ftMemo,ftFMTMemo,ftFixedChar,ftWideString];</li>
  <li>fTimeTypes:=[ftDate,ftTime,ftDateTime,ftTimeStamp];</li>
  <li><p>after the procedure is completely finished the timer is disabled and controls are enabled again.</p>
  
  <pre><code>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); //&lt;--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)&lt;&gt;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;
  </code></pre></li>
  </ul>