Skip to content

Commit

Permalink
removed ICommand and put invoking method into TObservable
Browse files Browse the repository at this point in the history
  • Loading branch information
sglienke committed Jun 15, 2015
1 parent e4fa8b2 commit 999c351
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 71 deletions.
96 changes: 33 additions & 63 deletions SimpleMVVM.Binding.Components.pas
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,13 @@ interface
SimpleMVVM.Observable;

type
ICommand = interface
procedure Execute;
end;

TCommand = class(TInterfacedObject, ICommand)
private
fMethod: TRttiMethod;
fInstance: TObject;
procedure Execute;
public
constructor Create(const method: TRttiMethod; const instance: TObject);
end;

TBinding = class(TComponent)
private
fObservable: IObservable;
protected
procedure InitComponent; virtual;
function Initialize(const observable: IObservable): TFunc<TValue>; virtual;
procedure InitObservable(const observable: IObservable); virtual;
function InitGetValue(const observable: IObservable): TFunc<TValue>; virtual;
procedure SetComponent(const component: TComponent); virtual; abstract;
public
constructor Create(const component: TComponent;
Expand All @@ -56,40 +44,36 @@ TBinding<T: TComponent> = class(TBinding)
TComponentBinding = class(TBinding<TComponent>)
protected
fProperty: TRttiProperty;
function Initialize(const observable: IObservable): TFunc<TValue>; override;
function InitGetValue(const observable: IObservable): TFunc<TValue>; override;
public
constructor Create(const component: TComponent; const observable: IObservable;
const propertyName: string); reintroduce;
end;

TButtonBinding = class(TComponent)
private
fAction: ICommand;
TButtonBinding = class(TBinding<TButton>)
protected
fComponent: TButton;
procedure Initialize;
procedure HandleClick(Sender: TObject);
public
constructor Create(const component: TButton; const action: ICommand); reintroduce;
procedure InitComponent; override;
procedure InitObservable(const observable: IObservable); override;
end;

TEditBinding = class(TBinding<TEdit>)
protected
procedure HandleChange(Sender: TObject);
procedure InitComponent; override;
function Initialize(const observable: IObservable): TFunc<TValue>; override;
function InitGetValue(const observable: IObservable): TFunc<TValue>; override;
end;

TComboBoxBinding = class(TBinding<TComboBox>)
protected
procedure HandleChange(Sender: TObject);
procedure InitComponent; override;
function Initialize(const observable: IObservable): TFunc<TValue>; override;
function InitGetValue(const observable: IObservable): TFunc<TValue>; override;
end;

TLabelBinding = class(TBinding<TLabel>)
protected
function Initialize(const observable: IObservable): TFunc<TValue>; override;
function InitGetValue(const observable: IObservable): TFunc<TValue>; override;
end;

function GetBindingClass(const target: TObject; const expression: string): TBindingClass;
Expand All @@ -108,6 +92,8 @@ function GetBindingClass(const target: TObject; const expression: string): TBind
Result := TComboBoxBinding
else if (target is TLabel) and SameText(expression, 'Text') then
Result := TLabelBinding
else if (target is TButton) and SameText(expression, 'Click') then
Result := TButtonBinding
else
Result := nil;
end;
Expand Down Expand Up @@ -140,44 +126,22 @@ procedure TControlHelper.SetDisabled(const value: Boolean);
{$ENDREGION}


{$REGION 'TCommand'}

constructor TCommand.Create(const method: TRttiMethod; const instance: TObject);
begin
inherited Create;
fMethod := method;
fInstance := instance;
end;

procedure TCommand.Execute;
begin
fMethod.Invoke(fInstance, []);
end;

{$ENDREGION}


{$REGION 'TBinding'}

constructor TBinding.Create(const component: TComponent;
const observable: IObservable);
begin
inherited Create(component);
SetComponent(component);
fObservable := TDependentObservable.Create(
Initialize(observable),
procedure(const value: TValue)
begin
observable.Value := value;
end);
InitObservable(observable);
InitComponent;
end;

procedure TBinding.InitComponent;
begin
end;

function TBinding.Initialize(const observable: IObservable): TFunc<TValue>;
function TBinding.InitGetValue(const observable: IObservable): TFunc<TValue>;
begin
Result :=
function: TValue
Expand All @@ -186,6 +150,16 @@ function TBinding.Initialize(const observable: IObservable): TFunc<TValue>;
end;
end;

procedure TBinding.InitObservable(const observable: IObservable);
begin
fObservable := TDependentObservable.Create(
InitGetValue(observable),
procedure(const value: TValue)
begin
observable.Value := value;
end);
end;

{$ENDREGION}


Expand Down Expand Up @@ -218,7 +192,7 @@ constructor TComponentBinding.Create(const component: TComponent;
inherited Create(component, observable);
end;

function TComponentBinding.Initialize(
function TComponentBinding.InitGetValue(
const observable: IObservable): TFunc<TValue>;
begin
Result :=
Expand All @@ -240,23 +214,19 @@ function TComponentBinding.Initialize(

{$REGION 'TButtonBinding'}

constructor TButtonBinding.Create(const component: TButton;
const action: ICommand);
procedure TButtonBinding.HandleClick(Sender: TObject);
begin
inherited Create(component);
fComponent := component;
fAction := action;
Initialize;
fObservable.Value;
end;

procedure TButtonBinding.HandleClick(Sender: TObject);
procedure TButtonBinding.InitComponent;
begin
fAction.Execute;
fComponent.OnClick := HandleClick;
end;

procedure TButtonBinding.Initialize;
procedure TButtonBinding.InitObservable(const observable: IObservable);
begin
fComponent.OnClick := HandleClick;
fObservable := observable;
end;

{$ENDREGION}
Expand All @@ -274,7 +244,7 @@ procedure TEditBinding.InitComponent;
fComponent.OnChange := HandleChange;
end;

function TEditBinding.Initialize(const observable: IObservable): TFunc<TValue>;
function TEditBinding.InitGetValue(const observable: IObservable): TFunc<TValue>;
begin
Result :=
function: TValue
Expand Down Expand Up @@ -309,7 +279,7 @@ procedure TComboBoxBinding.InitComponent;
fComponent.OnChange := HandleChange;
end;

function TComboBoxBinding.Initialize(const observable: IObservable): TFunc<TValue>;
function TComboBoxBinding.InitGetValue(const observable: IObservable): TFunc<TValue>;
begin
Result :=
function: TValue
Expand All @@ -329,7 +299,7 @@ function TComboBoxBinding.Initialize(const observable: IObservable): TFunc<TValu

{$REGION 'TLabelBinding'}

function TLabelBinding.Initialize(const observable: IObservable): TFunc<TValue>;
function TLabelBinding.InitGetValue(const observable: IObservable): TFunc<TValue>;
begin
Result :=
function: TValue
Expand Down
13 changes: 7 additions & 6 deletions SimpleMVVM.Binding.pas
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ function CreateObservable(instance: TObject;
typ := prop.PropertyType;
end;
if i < High(expressions) then
instance := prop.GetValue(instance).AsObject;
instance := Result.Value.AsObject;
end;
end;
end;
Expand All @@ -186,7 +186,6 @@ procedure Bind(const target: TComponent; const targetExpression: string;
observable: IObservable;
typ: TRttiType;
method: TRttiMethod;
command: ICommand;
bindingClass: TBindingClass;
begin
observable := CreateObservable(source, sourceExpression);
Expand All @@ -196,16 +195,18 @@ procedure Bind(const target: TComponent; const targetExpression: string;
typ := ctx.GetType(source.ClassInfo);
method := typ.GetMethod(sourceExpression);
if Assigned(method) then
command := TCommand.Create(method, source);
observable := TObservable.Create(
function: TValue
begin
Result := method.Invoke(source, []);
end);
end;

Assert(Assigned(observable) or Assigned(command), 'expression not found: ' + sourceExpression);
Assert(Assigned(observable), 'expression not found: ' + sourceExpression);

bindingClass := GetBindingClass(target, targetExpression);
if Assigned(bindingClass) then
bindingClass.Create(target, observable)
else if (target is TButton) and SameText(targetExpression, 'Click') then
TButtonBinding.Create(TButton(target), command)
else
TComponentBinding.Create(target, observable, targetExpression);
end;
Expand Down
46 changes: 44 additions & 2 deletions SimpleMVVM.Observable.pas
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ interface
SysUtils;

type
IObservable = interface
IObservable = interface(IInvokable)
['{3F78EF38-FA16-4E08-AD8D-3FD9A5E44BEF}']
function GetValue: TValue;
procedure SetValue(const value: TValue);
Expand Down Expand Up @@ -51,6 +51,18 @@ TObservableBase = class(TInterfacedObject, IObservable)
destructor Destroy; override;
end;

TObservable = class(TObservableBase)
private
fGetter: TFunc<TValue>;
fSetter: TAction<TValue>;
protected
function GetValueNonGeneric: TValue; override; final;
procedure SetValueNonGeneric(const value: TValue); override; final;
public
constructor Create(const getter: TFunc<TValue>); overload;
constructor Create(const getter: TFunc<TValue>; const setter: TAction<TValue>); overload;
end;

TDependentObservable = class(TObservableBase)
protected
fValue: TValue;
Expand Down Expand Up @@ -80,7 +92,6 @@ TObservable<T> = class(TObservableBase, IObservable<T>)
public
constructor Create; overload;
constructor Create(const value: T); overload;
property Value: T read GetValue write SetValue;
end;

TDependentObservable<T> = class(TObservableBase, IObservable<T>)
Expand Down Expand Up @@ -115,6 +126,7 @@ implementation

function TValueHelper.ToType<T>: T;
begin
Result := Default(T);
if not TryAsType<T>(Result) then
// hardcode some simple conversions for demo purpose - use Spring4D value converter later
case Kind of
Expand Down Expand Up @@ -173,6 +185,36 @@ procedure TObservableBase.RegisterDependency;
{$ENDREGION}


{$REGION 'TObservable'}

constructor TObservable.Create(const getter: TFunc<TValue>);
begin
Create(getter, nil);
end;

constructor TObservable.Create(const getter: TFunc<TValue>;
const setter: TAction<TValue>);
begin
inherited Create;
fGetter := getter;
fSetter := setter;
end;

function TObservable.GetValueNonGeneric: TValue;
begin
RegisterDependency;
Result := fGetter;
end;

procedure TObservable.SetValueNonGeneric(const value: TValue);
begin
fSetter(value);
Changed;
end;

{$ENDREGION}


{$REGION 'TDependentObservable'}

constructor TDependentObservable.Create(const getter: TFunc<TValue>);
Expand Down

0 comments on commit 999c351

Please sign in to comment.