Einzelnen Beitrag anzeigen

Benutzerbild von Union
Union

Registriert seit: 18. Mär 2004
Ort: Luxembourg
3.492 Beiträge
 
Delphi 7 Enterprise
 
#17

AW: MVVM in der Realität

  Alt 12. Sep 2013, 15:23
Also ich habe einen Lösungsansatz, den ich in Ausschnitten beschreibe.

Die View ist ein normales TForm. Beim Erzeugen wird das Binding erstellt.
Delphi-Quellcode:
constructor TfrmMain.Create(AOwner: TComponent);
begin
  ViewModel := TViewModelKunde.create;
  inherited;

  // Binding einzeln erzeugen
  FBindingList := TBindingList.Create;
  FNameBindObject := TEditBinding.Create;
  FNameBindObject.Control := edtNameTest;
  FNameBindObject.ControlProp := 'Text';
  FNameBindObject.BindObject := ViewModel.Kunde;
  FNameBindObject.BindProp := 'Name';
  // Und hinzufügen
  FBindingList.Add(FNameBindObject);
  // Oder direkt
  FBindingList.Add(TEditBinding.Create(edtKdNrTest, ViewModel.Kunde, 'Text', 'Kdnr'));
  // Hier wird alles initialisiert
  FBindingList.Load;
end;
Im Viewmodel wird dann die UI-Relevante Logik implementiert, z.b. ob gespeichert werden darf.
unit Viewmodel.Kunde;

Delphi-Quellcode:
interface

uses Model.Kunde;

type
  TViewModelKunde = class
  strict private
    FKunde: TKunde;
    procedure SetKunde(const Value: TKunde);
    function GetCanSave: boolean;
  published
    constructor create;
    property Kunde : TKunde read FKunde write SetKunde;
    procedure Save;
    property CanSave : boolean read GetCanSave;
  end;

// Kann aus dem View heraus benutzt werden um festzustellen ob z.B. Speicherung zulässig
function TViewModelKunde.GetCanSave: boolean;
begin
  result := FKunde.IsValid;
end;
Und das Model stellet eben die Daten dar, in diesem Fall ganz schlicht.
Delphi-Quellcode:
unit Model.Kunde;

interface
uses
  System.Classes;

type
  MaxLen = class(TCustomAttribute)
  private
    FMaxLen : integer;
  public
    constructor Create(const ALength : integer); overload;
    // Per Konvention muss die Attribut-Property immer "Value" heißen
    property Value : integer read FMaxLen;
  end;

  TKunde = class
  strict private
    FName: string;
    FKdNr: integer;
    FStrasse: string;
    procedure SetKdNr(const Value: integer);
    procedure SetName(const Value: string);
    procedure SetStrasse(const Value: string);
    function GetIsValid: boolean;
  public
    property KdNr : integer read FKdNr write SetKdNr;
    [MaxLen(20)]
    property Name : string read FName write SetName;
    property Strasse : string read FStrasse write SetStrasse;
    property IsValid : boolean read GetIsValid;
  end;

implementation

{ TKunde }

function TKunde.GetIsValid: boolean;
begin
  result := (FKdNr > 0) and
            (FName <> '') and
            (FStrasse <> '');
end;

procedure TKunde.SetKdNr(const Value: integer);
begin
  FKdNr := Value;
end;

procedure TKunde.SetName(const Value: string);
begin
  FName := Value;
end;

procedure TKunde.SetStrasse(const Value: string);
begin
  FStrasse := Value;
end;

{ MaxLen }

constructor MaxLen.Create(const ALength: integer);
begin
  FMaxLen := ALength;
end;
Das ganze wird verbunden durch das Binding. Wenn ein Binding erzeugt wird mit z.b.
Delphi-Quellcode:
TEditBinding.Create(edtKdNrTest, ViewModel.Kunde, 'Text', 'Kdnr')
TEditBinding.Load
wird eigentlich nur folgendes festgelegt:

1. edtKdnrTest.Text entspricht ViewModel.Kunde.Kdnr
2. Evtl. im Model angelegte Attribute werden ausgelesen und in die UI eingetragen (Hier MaxLen)
3. Der OnExit Event wird durch einen eigenen Event überschrieben, der Original-Event wird intern gemerkt

Immer wenn jetzt der OnExit des Edit aufgerufen wird, wird zunächst der Inhalt an das Model übertragen und dann ein evtl. vorher vorhandener Original-Event aufgerufen.
Delphi-Quellcode:
procedure TCustomBinding.DoNotify(Sender: TObject);
begin
  Save;
  if Assigned(FOldNotify) then
    FOldNotify(Sender);
end;

procedure TCustomBinding.Save;
var
  AValue : Variant;
begin
  AValue := GetPropValue(FControl, FControlProp);
  SetPropValue(FBindObject, FBindProp, AValue);
end;
Ibi fas ubi proxima merces
sudo /Developer/Library/uninstall-devtools --mode=all
  Mit Zitat antworten Zitat