Moving Columns in a DBGrid seems to move the attached DataSet fields

后端 未结 3 1157
野的像风
野的像风 2021-02-19 23:40

I observed something last week that I did not expect, and will describe below. I am curious as to why this happens. Is it something internal to the TDataSet class, an artifact o

3条回答
  •  悲&欢浪女
    2021-02-20 00:27

    Wodzu posted a solution to the reordered Field problem that was specific to ADO DataSet, but he led me to a solution that is similar, and available for all DataSets (whether it is implemented properly in all DataSets is another issue). Note that neither this answer, nor Wodzu's, is actually an answer to the original question. Instead, it is a solution to the problem noted, whereas the question relates to where this artifact originates.

    The solution that Wodzu's solution lead me to was FieldByNumber, and it is a method of the Fields property. There are two interesting aspects to the use of FieldByNumber. First, you must qualify its reference with the Fields property of your DataSet. Second, unlike the Fields array, which takes a zero-based indexer, FieldByNumber is a method that takes a one-based parameter to indicate the position of the TField you want to reference.

    The following is an updated version of the Button1 event handler that I posted in my original question. This version uses FieldByNumber.

    procedure TForm1.Button1Click(Sender: TObject);
    var
      sl: TStringList;
      i: Integer;
    begin
      sl := TStringList.Create;
      try
        sl.Add('The Structure of ' + ClientDataSet1.Name +
          ' using FieldByNumber');
        sl.Add('- - - - - - - - - - - - - - - - - ');
        for i := 0 to ClientDataSet1.FieldCount - 1 do
          sl.Add(ClientDataSet1.Fields.FieldByNumber(i + 1).FieldName);
        ShowMessage(sl.Text);
      finally
        sl.Free;
      end;
    end;
    

    For the sample project, this code produces the following output, regardless of the orientation of the Columns in the associated DBGrid:

    The Structure of ClientDataSet1 using FieldByNumber
    - - - - - - - - - - - - - - - - - 
    StartOfWeek
    Label
    Count
    Active
    

    To repeat, notice that the reference to the underlying TField required FieldByNumber to be qualified with a reference to Fields. Furthermore, the parameter for this method must lie within the 1 to DataSet.FieldCount range. As a result, to refer to the first field in the DataSet, you use the following code:

    ClientDataSet1.Fields.FieldByNumber(1)
    

    Like the Fields array, FieldByNumber returns a TField reference. As a result, if you want to refer to a method that is specific to a particular TField class, you have to cast the returned value to the appropriate class. For example, to save the contents of a TBlobField to a file, you may have to do something like the following code:

    TBlobField(MyDataSet.Fields.FieldByNumber(6)).SaveToFile('c:\mypic.jpg');
    

    Note that I am not suggesting that you should reference TFields in a DataSet using integer literals. Personally, the use of a TField variable that gets initialized through a one time call to FieldByName is more readable, and is immune to changes in the physical order of a table's structure (though not immune to changes in the names of your fields!).

    However, if you have DataSets associated with DBGrids whose Columns can be reordered, and you reference the fields of these DataSets using integer literals as indexers of the Fields array, you may want to consider converting your code to use the DataSet.Fields.FieldByName method.

提交回复
热议问题