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 False zurü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 die when-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+S drückt oder den Speichern-Command auslöst. Das Add-in führt die Speicherlogik durch und setzt anschließend Dirty := 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.

Zuletzt geändert: den 15.03.2026 um 02:23