Как заставить TDBCheckBox обновлять свой DataField сразу после нажатия?

У меня есть форма с несколькими элементами управления, где первый TDBCheckBox это связано с DataField := 'enabled',

Когда флажок установлен, я хочу, чтобы все остальные элементы управления были включены / отключены.

procedure TMyAdapter.DataSourceDataChange(Sender: TObject; Field: TField);
var
  Enabled: Boolean;
begin
  Enabled := FModel.DataSet['enabled'].AsBoolean;
  FView.Label1.Enabled   := Enabled;
  FView.DBEdit1.Enabled  := Enabled;
  FView.Label2.Enabled   := Enabled;
  FView.DBEdit2.Enabled  := Enabled;
  FView.Label3.Enabled   := Enabled;
  FView.DBEdit3.Enabled  := Enabled;
  FView.Label4.Enabled   := Enabled;
  FView.DBEdit4.Enabled  := Enabled;
end;

Это работает только тогда, когда фокус покидает флажок или когда набор данных прокручивается (у меня также есть навигатор в этой форме).

Есть ли способ заставить флажок обновлять свое поле данных немедленно?

Или есть даже лучшая альтернатива для достижения того, что я описал?

3 ответа

Решение

Пара проблем с использованием события DataChange для таких вещей заключается в том, что

  • Он вызывается гораздо чаще, чем вам нужно, чтобы реагировать на нажатие вашего DBCheckBox и

  • Выполнение.Post для набора данных приведет к изменению его состояния, что, как правило, является плохой идеей внутри события, которое само может быть вызвано изменением состояния набора данных.

То есть, лучше всего использовать стандартизированный способ решения подобных проблем, и я использую написать собственный обработчик сообщений, который выполняет ту работу, которую вы хотите, и вызывать его, используя PostMessage из вашего обработчика DBCheckBox1Click, как показано ниже:

const
      WM_AutoPost = WM_User + 1;
type
  TForm1 = class(TForm)
    [...]
  private
    procedure DoAutoPost;
    procedure WMAutoPost(var Msg : TMessage); message WM_Autopost;
  [...]
  end;

var
  Form1: TForm1;

implementation

[...]

procedure TForm1.DBCheckBox1Click(Sender: TObject);
begin
  PostMessage(Self.Handle, WM_AutoPost, 0, 0);
end;

procedure TForm1.DoAutoPost;
begin
  if CDS1.State in [dsEdit, dsInsert] then begin
    CDS1.Post;
    //  Update other controls here
  end;
end;

procedure TForm1.WMAutoPost(var Msg: TMessage);
begin
  DoAutoPost;
end;

Вы можете позвонить в DataSets UpdateRecord метод, позволяющий любому связанному элементу управления БД сохранять свои данные в базовом поле.

Это решение, которое я строю на основе ответов Uwe и MartynA:

procedure TMyAdapter.EnabledClick(Sender: TObject);
begin
  PostMessage(FView.Handle, WM_ENABLED_CLICKED, 0, 0);
end;

procedure TMyAdapter.WMEnabledClicked(var Msg: TMessage);
var
  DataSet: TDataSet;
begin
  DataSet := FView.EnabledCheckBox.Field.DataSet;
  if not (DataSet.State in [dsInsert, dsEdit]) then 
    DataSet.Edit;
  DataSet.UpdateRecord;
end;

procedure TMyAdapter.DataSourceDataChange(Sender: TObject; Field: TField);
var
  Enabled: Boolean;
begin
  if (Field = nil) or (Field = FView.EnabledCheckBox.Field) then
  begin
    Enabled := FView.EnabledCheckBox.Field.AsBoolean;
    FView.Label1.Enabled   := Enabled;
    FView.DBEdit1.Enabled  := Enabled;
    // etc.
  end;
end;
Другие вопросы по тегам