TmsFmxGrid binding issues

Hi,


I'm facing a issue with TmsFmxGrids, binded to a list aof object through an AdapterBindSource and a TListBindSourceAdapter<T>.

When a normal cell is modified, the value is correctly set in the linked object, but when a specific Editor is used, the new value is not set in the object, but appears in the grid.

The selection of the editor type is done with the event OnGetCellEditorType. I made tries with "CellEditorType:= etCombobox" and "CellEditorType:= etDatePicker".

Working on Delphi XE5 Update 2, with TMS Pack for FireMonkey V2.8.1.0.
Same Issue on TmsFmxLiveGrid.


Kind regards.

Hi, 


Did you set the Grid.Options.Editing.AutoPost property to apCell?
If the problem persist, can you give us a specific sample that we can use to reproduce this here and possibly find a solution to this issue?

Kind Regards, 
Pieter

Hi, 


Grid.Options.Editing.AutoPost property is set to apCell. I did not find any solution.

I did not find any way to upload my sample, i am giving you my code, just create a new firemonkey project and use this as main form.

if you edit Name or FirstName, there is no issue, but gender and birthday columns are not correctly set after modifying. To show it, i placed a ShowMessage in the afterpost event on the bindingSource.

.pas file:

unit Unit1;

interface

uses
  Data.Bind.EngExt, Fmx.Bind.DBEngExt, FMX.TMSGridDataBinding, System.Rtti, System.Bindings.Outputs,
  Fmx.Bind.Editors, Data.Bind.Components, Data.Bind.Grid, Data.Bind.ObjectScope, System.Classes,
  FMX.Types, FMX.Controls, FMX.TMSBaseControl, FMX.TMSGridCell, FMX.TMSGridOptions, FMX.TMSGridData,
  FMX.TMSCustomGrid, FMX.TMSGrid, FMX.Forms, System.Generics.Collections, FMX.Dialogs, FMX.ListBox,
  System.SysUtils;

type

  TPerson = class
  private
    FName: string;
    FFirstName: string;
    FGender: string;
    FBirthday: TDateTime;
  public
    property Name: string read FName write FName;
    property FirstName: string read FFirstName write FFirstName;
    property Gender: string read FGender write FGender;
    property Birthday: TDateTime read FBirthday write FBirthday;
    constructor Create(N, F, G: string; B: TDateTime);
  end;

  TForm1 = class(TForm)
    TMSFMXGrid1: TTMSFMXGrid;
    AdapterBindSource1: TAdapterBindSource;
    DataGeneratorAdapter1: TDataGeneratorAdapter;
    BindingsList1: TBindingsList;
    LinkGridToDataSourceAdapterBindSource: TLinkGridToDataSource;
    procedure AdapterBindSource1CreateAdapter(Sender: TObject;
      var ABindSourceAdapter: TBindSourceAdapter);
    procedure FormDestroy(Sender: TObject);
    procedure TMSFMXGrid1GetCellEditorType(Sender: TObject; ACol, ARow: Integer;
      var CellEditorType: TTMSFMXGridEditorType);
    procedure TMSFMXGrid1GetCellEditorProperties(Sender: TObject; ACol, ARow: Integer;
      CellEditor: TFmxObject);
  private
    FPersonList: TObjectList<TPerson>;
    procedure InitFPersonList;
    procedure AfterPostPerson(Adapter: TBindSourceAdapter);
  public
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

const
  COL_NAME = 0;
  COL_FIRSTNAME = COL_NAME + 1;
  COL_GENDER = COL_FIRSTNAME + 1;
  COL_BIRTHDAY = COL_GENDER + 1;

  // Values used in combobox
  MALE_STR = 'Male';
  FEMALE_STR = 'Female';

constructor TPerson.Create(N, F, G: string; B: TDateTime);
begin
  FName:= N;
  FFirstName:= F;
  FGender:= G;
  FBirthday:= B;
end;

// create the connection between the adapter bind source connected to the grid, and a list of person.
procedure TForm1.AdapterBindSource1CreateAdapter(Sender: TObject;
  var ABindSourceAdapter: TBindSourceAdapter);
begin
  InitFPersonList;
  ABindSourceAdapter:= TListBindSourceAdapter<TPerson>.Create(Self, FPersonList, False);
  ABindSourceAdapter.AfterPost:= AfterPostPerson;
end;

// uses to show a Person's stored values after editing
procedure TForm1.AfterPostPerson(Adapter: TBindSourceAdapter);
begin
  if Assigned(Adapter.Current) then
    with Adapter.Current as TPerson do
      ShowMessage(FirstName + ' ' + Name + ' - ' + Gender + ' - ' + DateToStr(BirthDay));
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  if (Assigned(FPersonList)) then FPersonList.Free;
end;

// create a sample list of person, shown in the grid
procedure TForm1.InitFPersonList;
begin
  if (Assigned(FPersonList)) then FPersonList.Free;
  FPersonList:= TObjectList<TPerson>.Create;
  FPersonList.Add(TPerson.Create('Dupond', 'Jean', MALE_STR, EncodeDate(1985, 1, 13)));
  FPersonList.Add(TPerson.Create('Simon', 'Marie', FEMALE_STR, EncodeDate(1999, 3, 20)));
end;

procedure TForm1.TMSFMXGrid1GetCellEditorProperties(Sender: TObject; ACol, ARow: Integer;
  CellEditor: TFmxObject);
begin
  // initialize combobox list of values
  if (ACol = COL_GENDER) then
    with CellEditor as TComboBox do
    begin
      Items.Clear;
      Items.Add(MALE_STR);
      Items.Add(FEMALE_STR);
    end;
end;

procedure TForm1.TMSFMXGrid1GetCellEditorType(Sender: TObject; ACol, ARow: Integer;
  var CellEditorType: TTMSFMXGridEditorType);
begin
  // define custom editors
  case ACol of
    COL_GENDER: CellEditorType:= TTMSFMXGridEditorType.etComboBox;
    COL_BIRTHDAY: CellEditorType:= TTMSFMXGridEditorType.etDatePicker;
  end;
end;

end. 
// end of .pas file

fmx file :

object Form1: TForm1
  Left = 0
  Top = 0
  Caption = 'Form1'
  ClientHeight = 480
  ClientWidth = 739
  FormFactor.Width = 320
  FormFactor.Height = 480
  FormFactor.Devices = [dkDesktop, dkiPhone, dkiPad]
  OnDestroy = FormDestroy
  DesignerMobile = False
  DesignerWidth = 0
  DesignerHeight = 0
  DesignerDeviceName = ''
  DesignerOrientation = 0
  DesignerOSVersion = ''
  object TMSFMXGrid1: TTMSFMXGrid
    Align = alClient
    DisableFocusEffect = False
    Height = 464.000000000000000000
    Margins.Left = 8.000000000000000000
    Margins.Top = 8.000000000000000000
    Margins.Right = 8.000000000000000000
    Margins.Bottom = 8.000000000000000000
    TabOrder = 0
    Width = 723.000000000000000000
    DefaultRowHeight = 24.000000000000000000
    DefaultColumnWidth = 100.000000000000000000
    FixedColumns = 0
    ColumnCount = 0
    RowCount = 201
    Options.Editing.CalcFormat = '%g'
    Options.Grouping.CalcFormat = '%g'
    Options.Grouping.GroupCountFormat = '(%d)'
    Options.IO.XMLEncoding = 'ISO-8859-1'
    Options.Mouse.TouchScrollingSensitivity = 0.100000001490116100
    Options.Printing.PageNumberFormat = '%g'
    Version = '2.2.0.4'
    Fill.Kind = bkSolid
    Stroke.Kind = bkSolid
    StrokeThickness = 1.000000000000000000
    TopRow = 0
    LeftCol = 0
    OnGetCellEditorType = TMSFMXGrid1GetCellEditorType
    OnGetCellEditorProperties = TMSFMXGrid1GetCellEditorProperties
    Columns = <
      item
        BorderWidth = 1.000000000000000000
        Color = claNull
        Editor = etEdit
        Fixed = False
        FixedFont.Style = [fsBold]
        FixedFontColor = claBlack
        FontColor = claBlack
        ID = ''
        Width = 100.000000000000000000
      end
      item
        BorderWidth = 1.000000000000000000
        Color = claNull
        Editor = etEdit
        Fixed = False
        FixedFont.Style = [fsBold]
        FixedFontColor = claBlack
        FontColor = claBlack
        ID = ''
        Width = 100.000000000000000000
      end
      item
        BorderWidth = 1.000000000000000000
        Color = claNull
        Editor = etEdit
        Fixed = False
        FixedFont.Style = [fsBold]
        FixedFontColor = claBlack
        FontColor = claBlack
        ID = ''
        Width = 100.000000000000000000
      end
      item
        BorderWidth = 1.000000000000000000
        Color = claNull
        Editor = etEdit
        Fixed = False
        FixedFont.Style = [fsBold]
        FixedFontColor = claBlack
        FontColor = claBlack
        ID = ''
        Width = 100.000000000000000000
      end
      item
        BorderWidth = 1.000000000000000000
        Color = claNull
        Editor = etEdit
        Fixed = False
        FixedFont.Style = [fsBold]
        FixedFontColor = claBlack
        FontColor = claBlack
        ID = ''
        Width = 100.000000000000000000
      end>
  end
  object AdapterBindSource1: TAdapterBindSource
    AutoActivate = True
    OnCreateAdapter = AdapterBindSource1CreateAdapter
    Adapter = DataGeneratorAdapter1
    ScopeMappings = <>
    Left = 536
    Top = 360
  end
  object DataGeneratorAdapter1: TDataGeneratorAdapter
    FieldDefs = <>
    Active = True
    AutoPost = False
    Options = [loptAllowInsert, loptAllowDelete, loptAllowModify]
    Left = 536
    Top = 416
  end
  object BindingsList1: TBindingsList
    Methods = <>
    OutputConverters = <>
    Left = 20
    Top = 5
    object LinkGridToDataSourceAdapterBindSource: TLinkGridToDataSource
      Category = 'Liaisons rapides'
      DataSource = AdapterBindSource1
      GridControl = TMSFMXGrid1
      AutoBufferCount = False
      Columns = <>
    end
  end
end



Hi, 


Thank you for your sample, 
We have investigated and improved this here.
The next version will address these issues.

Kind Regards, 
Pieter

Ok, thanks.

But I have some bad news : while trying to find a workaround, I found another issue.

You can reproduce it with the same sample project : Edit the name of a person and validate your modification by pressing "enter", then change the selected row using the arrow keys. The name of the first selected Person is modified another time. If you change the selected column before changing row, the field linked to the selected columns will change.

Kind regards.

Hi, 


We will investigate this issue here and try to find a workaround.

Kind Regards, 
Pieter

Hi,


I made an update to the 2.8.1.2 version this morning. 

The first reported issue (i.e: using custom editors) does not appear anymore. But the second issue (i.e: validating using "entrer" key and navigating with arrow keys still goes on.

Kind regards.

Hi again,


I think i found the problem :
when a Editor is visible, if Enter is pressed, TTMSFMXGrid.CellEditKeyDown is called. through   inheritance, TTMSFMXCustomGrid.CellEditBtnKeyDown is called to.

TTMSFMXCustomGrid.CellEditBtnKeyDown, hides the editor and post the modification, but then, TTMSFMXGrid.CellEditKeyDown calls NotifyObserverStartEdit so the bindsource is reset to edit mode.



Hi, 


We are currently investigating this here and are searching for a solution.

Kind Regards, 
Pieter

Pieter Scheldeman2015-02-27 10:03:42

Hi 


this is the solution i found : It's maybe not the best way to correct this issue, but it seems to work.

procedure TTMSFMXGrid.CellEditKeyDown(Sender: TObject; var Key: Word;
  var KeyChar: WideChar; Shift: TShiftState);
var
  c: Integer;
  obj: TColumnDescObject;
  dts: TBaseLinkingBindSource;
  ds: TDataSet;
  dso: TBaseObjectBindSource;
begin
  if ColumnDescList.Count = 0 then
  begin
    inherited;
    Exit;
  end;

  if Key <> vkEscape then
  begin
    inherited;
    if (Editing) or (Assigned(ActiveEditControl)) then // ADD
    begin // ADD
      c := ColumnIndex;
      if (c >= 0) and (c <= ColumnDescList.Count - 1) then
      begin
        obj := TColumnDescObject(ColumnDescList.Items[c]);
        if Assigned(obj) then
        begin
          dts := obj.ColumnDesc.DataSource;
          if Assigned(dts) then
          begin
            if dts is TCustomBindSourceDB then
            begin
              ds := (dts as TCustomBindSourceDB).DataSet;
              if Assigned(ds) then
              begin
                BlockUpdate := True;
                if not (ds.State = dsEdit) then
                  NotifyObserverStartEdit;
                BlockUpdate := False;
              end;
            end
            else if dts is TBaseObjectBindSource then
            begin
              dso := (dts as TBaseObjectBindSource);
              if Assigned(dso) then
              begin
                BlockUpdate := True;
                if not (dso.Editing) then
                  NotifyObserverStartEdit;
                BlockUpdate := False;
              end;
            end;
          end;
        end;
      end;
    end; //ADD
  end
  else [...]

I hope, this will be helpfull.
Kind regards.

Hi, 


Thank you for your feedback, 
we will look in to this issue as soon as possible.

Kind Regards, 
Pieter

Hi, 


We have investigated this here and have applied the fix, the next version will address this issue.

Kind Regards,
Pieter

Pieter Scheldeman2015-03-03 09:15:45