unit uPropertyObserver;

interface

uses
  Rtti, Classes;

type
  TProc = reference to procedure;
  TPropertyObserver = class
  private
    fTerminated : boolean;
  public
    constructor Create(aInstance : TObject; aPropertyName : string; aOnChange : TProc);
    procedure Terminate;
  end;

implementation

uses
  SysUtils, TypInfo;

{ TPropertyObserver }

constructor TPropertyObserver.Create(aInstance: TObject; aPropertyName: string; aOnChange : TProc);
begin
  TThread.CreateAnonymousThread(procedure
  var
    ctx : TRttiContext;
    t : TRttiType;
    oldValue, curValue : TValue;
    b : boolean;
    p : TRttiProperty;
  begin
    ctx := TRttiContext.Create;
    try
      t := ctx.GetType(aInstance.ClassType);
      p := t.GetProperty(aPropertyName);
      oldValue := p.GetValue(aInstance);
      while not fTerminated do
      begin
        curValue := p.GetValue(aInstance);
        b := false;
        case curValue.Kind of
          tkInt64,
          tkEnumeration,
          tkInteger: b := oldValue.AsOrdinal = curValue.AsOrdinal;
          tkWChar,
          tkLString,
          tkWString,
          tkString,
          tkUString,
          tkChar: b := oldValue.AsString = curValue.AsString;
          tkFloat: b := oldValue.AsExtended = curValue.AsExtended;

          tkUnknown: ;
          tkSet: ;
          tkClass: ;
          tkMethod: ;
          tkVariant: ;
          tkArray: ;
          tkRecord: ;
          tkInterface: ;
          tkDynArray: ;
          tkClassRef: ;
          tkPointer: ;
          tkProcedure: ;
        end;
        if not b then
        begin
          aOnChange;
          oldValue := curValue;
        end;
        sleep(10);
      end;
      finally
      ctx.Free;
    end;
  end).Start;
end;

procedure TPropertyObserver.Terminate;
begin
  fTerminated := true;
end;

end.

