Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Custom Property Editor Streaming (https://www.delphipraxis.net/177815-custom-property-editor-streaming.html)

mcbain 28. Nov 2013 16:15

Custom Property Editor Streaming
 
Hallo,
ich habe eine eigene Komponente, die wiederum ein Attribut vom Typ TOwnedCollection beinhaltet.
Wenn die Eigenschaft im Inspector angeklickt wird, wird mein eigener Property-Editor aufgerufen, indem ich die CollectionItems darin editieren, hinzufügen und löschen kann.
Das funktioniert auch alles. Nur wird meine Collection nicht in der DFM gespeichert. Somit ist die Collection nach einem Neuladen des Projekts natürlich wieder leer.
Ändere ich allerdings zugleich z.B. den Namen der Komponente und speichere das Projekt ab, wird meine Collection richtig in die DFM geschrieben und kann später auch wieder korrekt geladen werden.
Ich müsste also die IDE darüber informieren können, dass nun die Eigenschaft geändert wurde und diese in die DFM gespeichert werden muss.

Hier mein Code:
Aufruf des Editors:
Code:
procedure TMyEditor.Edit;
var lform: TMyForm;
begin
  lform := TMyForm.Create(nil);
  try
    lform.MyData:= TMyData(GetOrdValue);
    lform.ShowModal;

  finally
    FreeAndNil(lform);
  end
end {Edit};
In meiner Form TMyForm verändere ich anschließend etwas an der Collection.
Jetzt die Frage, wie schreibe ich dann innerhalb meiner TMyForm in die DFM zurück?

DefineProperties + TReader + TWriter sind ja dazu nicht nötig oder?

Es wäre nett, wenn mir jemand helfen könnte.
Vielen Dank.
Gruß
mc

mcbain 29. Nov 2013 07:25

AW: Custom Property Editor Streaming
 
Hier noch etwas mehr Information.
Ich habe meine Struktur eigentlich genauso wie hier von Mabuse beschrieben:

Zitat:

Zitat von MaBuSE (Beitrag 528120)
Zitat:

Zitat von Neutral General
@ MaBuSE Edit: Ja das weiß ich ja... Guck mal

EDIT: Der Editor ist noch nicht so schön aber das is ja auch nur mal um zu gucken obs geht.. das die ListBox nach dem start so klein ist, kommt von ner Art AutoSize-Funktion die das Ding hat ;)

Dein Problem ist folgendes:

Normale Properties werden direkt in der Formulardatei (*.dfm) gespeichert.
Mit Objekten funktioniert das aber nicht.

Du mußt Dich also selbst darum kümmern die Infos in der DFM zu speichern.

Hier findest Du weitere Infos: Delphi-Referenz durchsuchenDefineProperties (Methode von TComponent)


Das müsste so oder so ähnlich gehen.
(Habe ich jetzt nicht in Delphi getestet ;-) )

Delphi-Quellcode:
...
type
  TMyComp = class(TComponent)
  private
    FMyData: TMyData;
    procedure ReadMyData(Reader: TReader);
    procedure WriteMyData(Writer: TWriter);
...
  protected
    procedure DefineProperties(Filer: TFiler);
...
  published
    MyData: TMyData read FMyData write FMyData;
...

procedure TMyComp.DefineProperties(Filer: TFiler);
  function WriteData: Boolean;
  begin
    if Filer.Ancestor <> nil then
      Result := not FMyData.IsEqual(TMyComp(Filer.Ancestor).FMyData) else
      Result := FMyData.Count > 0;
  end;

begin
  inherited DefineProperties(Filer);
  Filer.DefineProperty('MyData', ReadMyData, WriteMyData, WriteData);
end;

procedure TMyComp.ReadMyData(Reader: TReader);
begin
  Reader.ReadValue;
  Reader.ReadCollection(MyData);
end;

procedure TMyComp.WriteMyData(Writer: TWriter);
begin
  Writer.WriteCollection(MyData);
end;
...

Hier mein Code:
Delphi-Quellcode:
...
type
  TMyObject= class(TCollectionItem)
    private
      FID: string;
      procedure SetID(aValue: string);
    published
      constructor Create(Collection: TCollection); override;
      destructor Destroy; override;
      property ID: string read FID write SetID;    
  end;


  TMyData= class(TOwnedCollection)
    private
      function GetItem(Index: Integer): TMyObject;
      procedure SetItem(Index: Integer; const Value: TMyObject);
    public
      function Add: TMyObject; reintroduce;
      function Insert(Index: Integer): TMyObject; reintroduce;
      property Items[Index: Integer]: TMyObjectread GetItem write SetItem;
  end;

 
  TMyComp = class(TComponent)
  private
    FMyData: TMyData;
    procedure ReadMyData(Reader: TReader);
    procedure WriteMyData(Writer: TWriter);
...
  protected
    procedure DefineProperties(Filer: TFiler); override;
...
  public
    MyData: TMyData read FMyData write FMyData;
...

procedure TMyComp.DefineProperties(Filer: TFiler);
begin
  inherited DefineProperties(Filer);
  Filer.DefineProperty('MyData', ReadMyData, WriteMyData, True);
end;

procedure TMyComp.ReadMyData(Reader: TReader);
begin
  Reader.ReadValue;
  Reader.ReadCollection(MyData);
end;

procedure TMyComp.WriteMyData(Writer: TWriter);
begin
  Writer.WriteCollection(MyData);
end;
...
Aber leider wird bei dieser Art und weise die Collection erst in dei DFM gespeichert, wenn ich eine andere Eigenschaft im ObjectInspector verändere. Ändere ich die Collection in meinem Custom-Property-Editor, passiert nichts.

Interessanterweise wird die Collection 2 Mal in die DFM geschrieben.

Kann mir diesbezüglich jemand nen Tip geben bitte? Bin etwas ratlos.
Vielen Dank.
Gruß
mc

Uwe Raabe 29. Nov 2013 08:16

AW: Custom Property Editor Streaming
 
Zitat:

Zitat von mcbain (Beitrag 1237873)
Interessanterweise wird die Collection 2 Mal in die DFM geschrieben.

Collections werden vom Streaming-System von Haus aus schon korrekt behandelt. Lass mal das DefineProperties weg.

mcbain 29. Nov 2013 09:56

AW: Custom Property Editor Streaming
 
Danke für den Hinweis Uwe Raabe.

Das behebt das Problem mit den doppelten Einträgen, jedoch wird immer noch nicht in die DFM geschrieben, sobald ich in meinem Property-Editor Veränderungen vornehme. Es wird erst gespeichert, wenn ich eine andere Eigenschaft verändere und speichere.

Könntest du mir auch hier weiterhelfen?

mcbain 29. Nov 2013 10:00

AW: Custom Property Editor Streaming
 
OK, ich hab mein Problem festgestellt.
"Alles Speichern" wird nicht getriggert in der IDE, wenn ich in meinem Property-Editor etwas an meiner Collection verändere.
Somit wird natürlich die Änderung nicht registriert und die IDE schreibt nicht in die DFM zurück, wenn ich das Projekt schließe.

Klicke ich auf "Speichern" wird schon korrekt in die DFM zurückgeschrieben.

Kann ich irgendwie "Alles Speichern" in der IDE über meinen Property-Editor triggern?

EDIT: Ah, ich glaube ich weiß woran es liegt, ich habe in meiner Collection vergessen die Methoden Update und Notify zu überschreiben. Das probiere ich gleich mal aus.

mcbain 29. Nov 2013 11:50

AW: Custom Property Editor Streaming
 
Hmmm...funktioniert immer noch nicht.
Ich hab jetzt in SetID von TMyObject einen Change(false) eingebaut und in der Collection TMyData Notify und Update überschrieben.

Allerdings wird die Änderung immer noch nicht von der IDE registriert, wenn ich etwas an der Collection ändere.

Uwe Raabe 29. Nov 2013 12:00

AW: Custom Property Editor Streaming
 
Hast du bei TMyObject auch Assign überschrieben?

mcbain 29. Nov 2013 12:18

AW: Custom Property Editor Streaming
 
Ja, hier der Ausschnitt:
Code:
procedure TMyObject.Assign(Source: TPersistent);
begin
  if Source is TMyObject then
  begin
    FId := TMyObject (Source).FId;
  end
  else
    inherited; //raises an exception
end;

procedure TMyObject.SetID(aValue: string);
begin
  if FID <> aValue then
  begin
    FID := aValue;
    Changed(false);
  end;
end;

procedure TMyData.Notify(Item: TCollectionItem;
  Action: TCollectionNotification);
begin
  inherited;
  TMyComp(Owner).Updated;
end;

procedure TMyData.Update(Item: TCollectionItem);
begin
  inherited;
  TMyComp(Owner).Updated;
end;
Ach ja und mein Property-Editor-Formular zum Ändern der Collection sieht so aus:

Code:
procedure TMyForm.FormShow(Sender: TObject);
 if MyData <> nil then
    begin
      for i := 0 to MyData.Count -1  do
      begin
        myObject:= MyData.Items[i];
        lbx.AddItem(myObject.ClassName,myObject);
      end;
    end;
end;

procedure TMyForm.btnSaveClick(Sender: TObject);
var myObject: TMyObject;
begin
 myObject := (lbx.Items.Objects[0] as TMyObject);
 myObject .ID := '1234';
end;

stahli 29. Nov 2013 12:51

AW: Custom Property Editor Streaming
 
Einen Propertyeditor habe ich gerade nicht zur Hand. Aber in meinem Komponenteneditor rufe ich Designer.Modified auf.
Schau mal nach einer analogen Anweisung.

Delphi-Quellcode:
procedure TssLayoutComponentEditor.ShowDesigner;
var
  DesignerForm: TFormSsLayoutEditor;
begin
  if (Component is TssLayout) then
  begin
    DesignerForm := TFormSsLayoutEditor.Create(nil);
    try
      DesignerForm.ssLayoutIDE := (Component as TssLayout);
      DesignerForm.AssignLayoutIDEtoDTE;
      DesignerForm.ShowModal;
      DesignerForm.AssignLayoutDTEtoIDE;
      DesignerForm.ssLayoutIDE := nil;
      Designer.Modified;
    finally
      DesignerForm.Free;
    end;
  end;
end;

mcbain 2. Dez 2013 06:25

AW: Custom Property Editor Streaming
 
Designer.Modified war die Lösung:

Code:
procedure TMyEditor.Edit;
var lform: TMyForm;
begin
  lform := TMyForm.Create(nil);
  try
    lform.MyData:= TMyData(GetOrdValue);
    lform.ShowModal;
    Designer.Modified;

  finally
    FreeAndNil(lform);
  end
end {Edit};
Vielen Dank an stahli!


Alle Zeitangaben in WEZ +1. Es ist jetzt 14:06 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz