2006. április 29., szombat

How to synchronize two controls


Problem/Question/Abstract:

I have a frame with two panels on it (right and left). The left panel is a pretty standard treeview. The right panel is a representation of the data record for the selected node in the tree view. The right panel is dynamic, that is it is constructed on the fly at run time as the users have the ability to define what fields they wish to show and what the labels are for those fields.

I need the right panel to change the treeview node text when the record in the right panel is posted. The general consensus is that it'd best be done with a callback, but I've never done one before. Can anyone give me a simple example of how to do this?

Answer:

What you are describing is a Mediator Pattern. In essence, you set up a class which is aware of your two (or more) components. Set up properties to record changes and then in the appropriate event handler, simply assign the new values. The Mediator is solely responsible for synchronizing the two.

Very simple example (yours will be slightly more complex, but surprisingly probably won't have too much more code):

TEditBoxMediator = class
private
  FIsChanging: boolean;
  FFirstBox: TEdit;
  FSecondBox: TEdit;
  function GetText: string;
  procedure SetText(Value: string);
public
  property Text: string read GetText write SetText;
  constructor Create(const FirstBox, SecondBox: TEdit);
end;

constructor TEditBoxMediator.Create(const FirstBox, SecondBox: TEdit);
begin
  inherited Create;
  FFirstBox := FirstBox;
  FSecondBox := SecondBox;
  FIsChanging := False;
end;

function TEditBoxMediator.GetText: string;
begin
  Result := FFirstBox.Text;
end;

procedure TEditBoxMediator.SetText(Value: string);
begin
  if FIsChanging then
    Exit;
  FIsChanging := True;
  if FFirstBox.Text <> Value then
    FFirstBox.Text := Value;
  if FSecondBox.Text <> Value then
    FSecondBox.Text := Value;
  FIsChanging := False;
end;

procedure TForm1.Create {...}
begin
  FEditBoxMediator := TEditBoxMediator.Create(Edit1, Edit2);
end;

procedure TForm1.Edit1Change(Sender: TObject);
begin
  FEditBoxMediator.Text := Edit1.Text;
end;

and so on.


The idea is that the mediator handles the changes (and uses the internal flag to prevent an endless
loop).

Nincsenek megjegyzések:

Megjegyzés küldése