Создание компонента с поддержкой БД - TFieldDataLink.Edit вызывает перезагрузку полей

Я пытаюсь создать элемент управления с учетом данных. У меня есть объект TFieldDataLink с подключенными DataSource и Field. Казалось, все шло нормально, пока я не попытался отредактировать значение.

Я использую события OnDataChange и OnUpdateData для TFieldDataLink. Похоже, мне нужно вызвать TFieldDataLink.Edit, если я хочу, чтобы событие OnUpdateData вызывалось перед переходом к новой записи или публикации. В приведенном ниже примере кода я пытаюсь вызвать .Edit в поле OnExit элемента управления, если были внесены изменения. В моем реальном приложении элемент управления состоит из нескольких полей со списком поиска DevExpress, и я пытаюсь вызвать .Edit в OnEditValueChanged.

Моя проблема заключается в том, что вызов TFieldDataLink.Edit вызывает повторное срабатывание события OnDataChange. Это заставляет перезагрузить мое редактирование с исходным значением. Если я делаю второе изменение после того, как набор данных уже находится в режиме редактирования, событие OnDataChange не запускается.

Вот тестовый блок I, в котором все есть в одной форме. В моем реальном приложении это разделено на более сложный компонент.

Когда я должен вызывать .Edit без изменения OnUpdateData? Я знаю, что могу установить переменную-член, чтобы остановить перезагрузку или отключить события перед вызовом .Edit. Такое ощущение, что я чего-то не понимаю в объекте TFieldDataLink, и мне не нужно прибегать к этим трюкам.

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, uADStanIntf, uADStanOption, uADStanParam, uADStanError,
  uADDatSManager, uADPhysIntf, uADDAptIntf, Data.DB, uADCompDataSet, uADCompClient, Vcl.StdCtrls,
  Vcl.DBCtrls, Vcl.Mask, Vcl.ExtCtrls, Vcl.Grids, Vcl.DBGrids;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    DataSource1: TDataSource;
    ADMemTable1: TADMemTable;
    ADMemTable1test: TStringField;
    Button1: TButton;
    DBEdit1: TDBEdit;
    DBGrid1: TDBGrid;
    DBNavigator1: TDBNavigator;
    procedure FormCreate(Sender: TObject);
    procedure Edit1Exit(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    FMyDataLink: TFieldDataLink;
    procedure MyDataChange(Sender: TObject);
    procedure MyUpdateData(Sender: TObject);
  public

  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  AdMemTable1.CreateDataSet;

  FMyDataLink := TFieldDataLink.Create();
  FMyDataLink.DataSource := DataSource1;
  FMyDataLink.FieldName := 'test';

  FMyDataLink.OnDataChange := MyDataChange;
  FMyDataLink.OnUpdateData := MyUpdateData;


  AdMemTable1.Append;
  AdMemTable1.FieldByName('test').AsString := 'my test';
  AdMemTable1.Post;


end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FMyDataLink.OnDataChange := nil;
  FMyDataLink.OnUpdateData := nil;
  FMyDataLink.Free;
end;

procedure TForm1.Edit1Exit(Sender: TObject);
begin
  if Edit1.Modified = true then
  begin
    FMyDataLink.Edit;
    FMyDataLink.Modified;
  end;
end;


procedure TForm1.MyDataChange(Sender: TObject);
begin
  Edit1.Text := FMyDataLink.Field.AsString;
  Edit1.Modified := false;
end;


procedure TForm1.MyUpdateData(Sender: TObject);
begin
  FMyDataLink.Field.AsString := Edit1.Text
end;


end.

person Mark Elder    schedule 28.01.2014    source источник


Ответы (2)


TFieldDataLink.Edit только устанавливает источник данных в состояние редактирования (так же, как DataSet.Edit). Вам это не нужно здесь, но пример использования может быть:

procedure TMyCustomControl.DoPaste;
begin
  FMyDataLink.Edit;
  inherited DoPaste;
  FMyDataLink.Modified;
end;

Вместо этого вы хотите, чтобы при выходе из элемента управления обновлялась запись, если она была изменена:

procedure TForm1.Edit1Exit(Sender: TObject);
begin
  if Edit1.Modified then
    try
      FMyDataLink.UpdateRecord;
    except
      Edit1.SetFocus;
      raise;
    end;
end;

Что касается того, когда следует вызывать TFieldDataLink.Modified, обновили значение поля:

procedure TForm1.MyUpdateData(Sender: TObject);
begin
  FMyDataLink.Field.AsString := Edit1.Text;
  FMyDataLink.Modified;
end;
person NGLN    schedule 28.01.2014
comment
Если вы вызываете FMyDataLink.UpdateRecord без предварительного вызова FMyDataLink.Edit, события UpdateData никогда не вызываются, поэтому набор данных никогда не обновляется. Я не хочу сразу переводить набор данных в режим редактирования. Я хочу дождаться первого изменения, как это делают другие компоненты базы данных. Я просто не могу понять, как не потерять это первое изменение. - person Mark Elder; 29.01.2014
comment
Если в обработчике OnExit еще не вызывается FMyDataLink.Modified, то это ваша проблема. OnExit не нужно сигнализировать о том, что что-то изменилось; эта ответственность лежит, например, на обработчик OnChange файла Edit. - person NGLN; 30.01.2014
comment
Все еще не работает. Параметр Modified, по-видимому, только гарантирует, что для этого поля вызывается UpdateData. И это происходит только в том случае, если вызывается Edit, что возвращает меня к моей проблеме, заключающейся в том, что вызов редактирования после первого изменения вызывает перезагрузку. В случае TEdit, если я вызываю DataLink.Edit в событии OnChange и пытаюсь ввести букву в конце поля, мое редактирование очищается при перезагрузке, а курсор перемещается обратно в начало поля. текст. - person Mark Elder; 30.01.2014

Это старый вопрос, но для тех, кто сталкивается с той же проблемой, вам необходимо переопределить метод KeyPress элемента управления с поддержкой данных и вызвать метод FieldDataLink.Edit; после унаследованного; если Ключ действителен для ввода (в т.ч. del/c&p/bs/etc..). На данный момент текущие данные еще не изменены. Вызывать .Edit позже этого момента слишком поздно.

person Atys    schedule 10.03.2017