Inhaltsverzeichnis
TWvdSDocumentFrame
Der TWvdSDocumentFrame ist die Basisklasse für alle visuellen Inhalte, die ein Add-in bereitstellt — sowohl für Dokument-Tabs als auch für Sidebar-Panels. Er ist ein gewöhnlicher LCL-TFrame, den der Host in die Shell einbettet. Das Add-in gestaltet den Frame-Inhalt, der Host kümmert sich um den Rahmen: Tab-Titel, Icon, Dirty-State und Lebenszyklus.
Zurück zur SDK-Übersicht oder zur Hauptübersicht.
Warum ein Frame
Die Entscheidung für TFrame als Basisklasse ist bewusst getroffen. Ein Frame ist ein Container, der sich in beliebige übergeordnete Controls einbetten lässt, ohne ein eigenes Fenster zu erzeugen. Das unterscheidet ihn von einem TForm, das immer ein Top-Level-Fenster ist. Da der Host die Kontrolle über die Shell behält, darf ein Add-in kein eigenes Fenster erzeugen. Der Frame passt sich in das vom Host bereitgestellte Layout ein — sei es ein Dokument-Tab, ein Sidebar-Panel oder ein Bottom-Panel.
Dokumenttypen
Ein Add-in registriert Dokumenttypen über eine IWvdSDocumentFactory beim IDocumentService. Jeder Dokumenttyp hat eine eindeutige Bezeichnung und eine Art:
type TDocumentKind = ( dkSingleInstance, // Nur ein Tab dieses Typs gleichzeitig dkMultiInstance // Mehrere Tabs möglich );
- SingleInstance — Geeignet für Übersichtslisten, Einstellungsdialoge oder Dashboards. Wenn der Benutzer das Dokument erneut öffnet, aktiviert der Host den bestehenden Tab, statt einen neuen zu erzeugen.
- MultiInstance — Geeignet für Editoren, die mehrere Datensätze gleichzeitig offen halten. Jeder Aufruf erzeugt einen neuen Tab.
IWvdSDocumentFactory
type IWvdSDocumentFactory = interface function CreateFrame(AOwner: TComponent): TWvdSDocumentFrame; function GetDocumentType: string; function GetDocumentKind: TDocumentKind; function GetDisplayName: string; function GetIcon: string; end;
Die Factory erzeugt auf Anfrage einen neuen Frame. Der Host ruft CreateFrame auf, wenn ein Dokument geöffnet wird, und bettet den zurückgegebenen Frame in einen Tab ein. AOwner ist der Tab-Container des Hosts — der Frame wird automatisch freigegeben, wenn der Tab geschlossen wird.
GetDocumentType liefert den eindeutigen Typnamen (z.B. assets.editor). Dieser Name muss mit dem Wert übereinstimmen, der bei IDocumentService.OpenDocument verwendet wird.
// Beispiel: Factory-Implementierung type TAssetEditorFactory = class(TInterfacedObject, IWvdSDocumentFactory) function CreateFrame(AOwner: TComponent): TWvdSDocumentFrame; function GetDocumentType: string; function GetDocumentKind: TDocumentKind; function GetDisplayName: string; function GetIcon: string; end; function TAssetEditorFactory.CreateFrame(AOwner: TComponent): TWvdSDocumentFrame; begin Result := TAssetEditorFrame.Create(AOwner); end; function TAssetEditorFactory.GetDocumentType: string; begin Result := 'assets.editor'; end; function TAssetEditorFactory.GetDocumentKind: TDocumentKind; begin Result := dkMultiInstance; end;
TDocumentContext
Jeder geöffnete Dokument-Tab erhält einen TDocumentContext, über den das Add-in den Tab-Zustand steuern kann.
type IDocumentContext = interface procedure SetTitle(const ATitle: string); procedure SetIcon(const AIcon: string); procedure SetDirty(AValue: Boolean); function GetDirty: Boolean; procedure SetReadOnly(AValue: Boolean); function GetReadOnly: Boolean; end;
- Title — Der Text, der im Tab-Reiter erscheint. Bei Multi-Instance-Dokumenten typischerweise der Datensatzname.
- Icon — Pfad zum Tab-Icon. Wird relativ zum Add-in-Verzeichnis aufgelöst.
- Dirty — Zeigt an, ob der Frame ungespeicherte Änderungen hat. Der Host markiert den Tab mit einem Punkt oder Stern und fragt beim Schließen nach.
- ReadOnly — Zeigt an, ob der Inhalt schreibgeschützt ist. Der Host passt die Titelleiste entsprechend an.
Frame-Callbacks
Der TWvdSDocumentFrame stellt virtuelle Methoden bereit, die der Host bei bestimmten Ereignissen aufruft:
type TWvdSDocumentFrame = class(TFrame) protected function DoCanClose: Boolean; virtual; procedure DoActivate; virtual; procedure DoDeactivate; virtual; procedure DoSave; virtual; end;
- DoCanClose — Der Host ruft diese Methode auf, wenn der Benutzer den Tab schließen möchte. Das Add-in kann
Falsezurückgeben, um das Schließen zu verhindern, etwa wenn ungespeicherte Änderungen vorliegen. In diesem Fall zeigt das Add-in typischerweise einen „Speichern?“-Dialog an. - DoActivate — Wird aufgerufen, wenn der Tab aktiviert wird (der Benutzer wechselt zu diesem Tab). Hier kann das Add-in Kontextwerte setzen (
IHost.Context.SetContext), damit diewhen-Ausdrücke in Menüs und Toolbars korrekt ausgewertet werden. - DoDeactivate — Wird aufgerufen, wenn der Tab deaktiviert wird (der Benutzer wechselt zu einem anderen Tab). Hier kann das Add-in Kontextwerte zurücksetzen.
- DoSave — Wird aufgerufen, wenn der Benutzer
Strg+Sdrückt oder den Speichern-Command auslöst. Das Add-in führt die Speicherlogik durch und setzt anschließendDirty := False.
Vollständiges Beispiel
unit MyDocumentFrame; interface uses Classes, Controls, Forms, StdCtrls, WvdS.Document.Host.Api; type TMyDocumentFrame = class(TWvdSDocumentFrame) private FEdit: TMemo; FContext: IDocumentContext; procedure HandleEditChange(Sender: TObject); protected function DoCanClose: Boolean; override; procedure DoSave; override; procedure DoActivate; override; public constructor Create(AOwner: TComponent); override; procedure SetDocumentContext(const AContext: IDocumentContext); end; implementation constructor TMyDocumentFrame.Create(AOwner: TComponent); begin inherited; FEdit := TMemo.Create(Self); FEdit.Parent := Self; FEdit.Align := alClient; FEdit.OnChange := @HandleEditChange; end; procedure TMyDocumentFrame.SetDocumentContext(const AContext: IDocumentContext); begin FContext := AContext; FContext.SetTitle('Neues Dokument'); end; procedure TMyDocumentFrame.HandleEditChange(Sender: TObject); begin if Assigned(FContext) then FContext.SetDirty(True); end; function TMyDocumentFrame.DoCanClose: Boolean; begin if Assigned(FContext) and FContext.GetDirty then begin case MessageDlg('Speichern?', mtConfirmation, [mbYes, mbNo, mbCancel], 0) of mrYes: begin DoSave; Result := True; end; mrNo: Result := True; else Result := False; end; end else Result := True; end; procedure TMyDocumentFrame.DoSave; begin // Speicherlogik hier if Assigned(FContext) then FContext.SetDirty(False); end; procedure TMyDocumentFrame.DoActivate; begin // Kontextwerte setzen, damit Menüs korrekt reagieren end; end.
Ein durchgehendes Tutorial mit Factory und Registrierung findet sich unter Tutorial: Document-View Add-in.
Weiter zur Inter-Add-in-Kommunikation oder zurück zur SDK-Übersicht.