Einzelnen Beitrag anzeigen

FAM

Registriert seit: 22. Dez 2014
47 Beiträge
 
Delphi XE Enterprise
 
#20

AW: MVC + Observer Pattern Konzept / Was haltet Ihr davon

  Alt 6. Feb 2015, 10:01
..., erfolgt das Anhängen an den PropertyChanged Event auch eben in dieser Basis View -> weniger Arbeit für mich
da ich jetzt nicht den luxus eines Frameworks habe mache ich das jetzt "per Hand"

@Sir: eine Frage noch
wie kann ich es erreichen das ich bei notify einen parameter mit übergeben kann?
nach dem Motto notify(para1); ?


Delphi-Quellcode:
procedure TStockpileModel.SetData(data: TArray<Double>);
begin
  self.data := data;
  // alle Ereignis-Behandlungs-Routinen der Liste aufrufen
  // wurde mit registerOn an das Model regestriert
  notify;
end;

BasisModel

Als erstes erstes erstelle ich mir mal eine Basis Model, mit PropertyChanged-Handling TModel.notify davon abgeleitete Klasse müssen bei Setter-Methoden jetzt die Funktion notify aufrufen

Delphi-Quellcode:
unit model;

interface

type
  TEvent = procedure of object;

  TModel = class
  protected
    // interne Liste
    OnChange: array of TEvent;
    // Aufruf aller Routinen der Liste
    procedure notify;
    destructor destroy; override;
  public
    // neuer 'Event-Handler' in Liste
    procedure registerOn(routine: TEvent);
    // 'Event-Handler' aus Liste entfernen
    procedure registerOff(routine: TEvent);
  end;

implementation

// registriert neue routinen an den controller
procedure TModel.registerOn(routine: TEvent);
var
  n: integer;
begin
  n := Length(OnChange);
  SetLength(OnChange, n + 1);
  OnChange[n] := routine;
end;

// de-registriert routinen vom controller
procedure TModel.registerOff(routine: TEvent);
var
  i, j: integer;
begin
  i := Low(OnChange);
  while i <= High(OnChange) do // High liefert -1 bei leerem Array
  begin
    if @OnChange[i] = @routine // mit '@' nur Adressen vergleichen
    then
    begin
      for j := i to High(OnChange) - 1 do
        OnChange[j] := OnChange[j + 1];
      SetLength(OnChange, Length(OnChange) - 1);
    end
    else
      i := i + 1;
  end;
end;

// alle Ereignis-Behandlungs-Routinen der Liste aufrufen
destructor TModel.destroy;
begin
//
  inherited;
end;

procedure TModel.notify;
var
  i: integer;
begin
  for i := Low(OnChange) to High(OnChange) do
    OnChange[i];
end;

end.
Eigentliches Model

TViewModel.SetBar(const Value: String); hier könnte die   notify; Methoden-Aufruf weggelasen wird

Delphi-Quellcode:
unit model.stockpile;

interface

uses
  model;

type

  { Stockpile Model }
  TStockpileModel = class(TModel)
  private
    data: TArray<Double>;
    cdsBioLife: String;

    function GetBioLife: String;

  public
    function GetData: TArray<Double>;
    procedure SetData(data: TArray<Double>);
    property BioLife: String read GetBioLife;
    destructor destroy; override;

  end;

implementation

{ TStockpileModel }

destructor TStockpileModel.destroy;
begin
  inherited;
end;

function TStockpileModel.GetBioLife: String;
begin
  Result := cdsBioLife;
end;

function TStockpileModel.GetData: TArray<Double>;
begin
  Result := self.data;
end;

procedure TStockpileModel.SetData(data: TArray<Double>);
begin
  self.data := data;
  // alle Ereignis-Behandlungs-Routinen der Liste aufrufen
  // wurde mit registerOn an das Model regestriert
  notify;
end;

end.
Dann das ViewModel

Delphi-Quellcode:
unit ViewModel;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, jpeg, StdCtrls, pngimage, JvPanel, JvExExtCtrls,
  JvExtComponent, Series, TeeShape, TeEngine, TeeProcs, Chart, Math, TeeGDIPlus,
  ComCtrls, JvExComCtrls, JvComCtrls, model, model.stockpile,
  controller, dOPCIntf, dOPCComn, dOPCDA, dOPC;

implementation

type

  TViewModel = class(TModel)

  private
    FModel: TStockpileModel;
    FBar: String;
    FFoo: string;
    function GetBioLifeCDS: String;
    function GetFishPictures: TBitmap;

    procedure SetBar(const Value: String);
    procedure SetFoo(const Value: string);
  public
    constructor Create;
    destructor Destroy; override;

    property BioLifeCDS: String read GetBioLifeCDS;
    property FishPictures: TBitmap read GetFishPictures;

    property Foo: string read FFoo write SetFoo;
    property Bar: String read FBar write SetBar;

  end;

  { TViewModel }

constructor TViewModel.Create;
begin
  inherited Create;
  FModel := TStockpileModel.Create;
end;

destructor TViewModel.Destroy;
begin
  FModel.Free;
  inherited;
end;

procedure TViewModel.SetBar(const Value: String);
begin
  if FBar <> Value then
  begin
    FBar := Value;
    notify;
  end;
end;

procedure TViewModel.SetFoo(const Value: string);
begin
  if FFoo <> Value then
  begin
    FFoo := Value;
    notify;
    // OnPropertyChanged('Foo');
  end;
end;

function TViewModel.GetBioLifeCDS: String;
begin
  Result := FModel.BioLife;
end;

function TViewModel.GetFishPictures: TBitmap;
begin
  try
    Result := TBitmap.Create;
    Result.LoadFromFile
      (ExpandFileName(IncludeTrailingPathDelimiter(ExtractFileDir(ParamStr(0)) +
      '') + '../../Assets/Images/sidebar-icon-error.jpg'));

  finally
  end;

end;

end.
Main

Delphi-Quellcode:
....

// Model
    FViewModel: TStockpileModel;

    // Model wurde geändert
    procedure ViewModelPropertyChanged(Sender: TObject);



implementation


FViewModel := TViewModel.Create;

// Wenn model geändert wird -> ViewModelPropertyChanged ausführen
FViewModel.registerOn(ViewModelPropertyChanged);


// Daten aus dem Model holen und GUI updaten
procedure TForm1.ViewModelPropertyChanged(Sender: TObject);
begin
  EditContentbarStartMarker.Text := FViewModel.Foo;
end;

// Daten ins Model zurückschreiben
procedure TForm1.EditContentbarEndMarkerChange(Sender: TObject);
begin
  FViewModel.Foo := TEdit(Sender).Text;
end;

Geändert von FAM ( 6. Feb 2015 um 10:06 Uhr)
  Mit Zitat antworten Zitat