Reputation: 14873
I have a form with several controls where the first one is a TDBCheckBox
that is bound to DataField := 'enabled'
.
When the checkbox is clicked I want all the remaining controls to be enabled / disabled.
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;
This only works when the focus leaves the checkbox or when the dataset is scrolled (I have a navigator on this form as well).
Is there a way to make the checkbox update its datafield immediately?
Or is there even a better alternative to achieve what I have described?
Upvotes: 2
Views: 2633
Reputation: 14873
This is the solution I build from input of the answers of Uwe and 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;
Upvotes: 2
Reputation: 47714
You can call the DataSets UpdateRecord
method to make any linked DB control store its data into the underlying field.
Upvotes: 3
Reputation: 30715
A couple of problems with using the DataChange event to do things like this are that
It's called a lot more frequently than you actually need, to react to your DBCheckBox being clicked and
Doing a .Post to the dataset is going to change its state, which is generally a bad idea inside an event which can itself be triggered by a change of dataset state.
Ime, it's best to use a standardised way of dealing with these sorts of problems and the one I use is to write a custom message handler that does the work you want, and to call it using PostMessage from your DBCheckBox1Click handler, as shown below:
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;
Upvotes: 2