AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language Bookmark and DisableControls - ein kleiner Trick mit Interfaces
Thema durchsuchen
Ansicht
Themen-Optionen

Bookmark and DisableControls - ein kleiner Trick mit Interfaces

Ein Thema von hschmid67 · begonnen am 1. Feb 2017 · letzter Beitrag vom 2. Feb 2017
Antwort Antwort
Seite 1 von 2  1 2      
hschmid67

Registriert seit: 2. Jul 2012
Ort: Weilheim i. Obb.
71 Beiträge
 
Delphi 12 Athens
 
#1

Bookmark and DisableControls - ein kleiner Trick mit Interfaces

  Alt 1. Feb 2017, 15:18
Delphi-Version: 2009
Hallo zusammen,

ich bitte um Eure Meinung zu folgendem Vorgehen bei einem für mich alltäglichen Programmierfall:

Sehr häufig stehe ich vor der Situation, dass ich mit einem Dataset (meist eine Komponente auf einem Datenmodul) etwas tun möchte, was aber den Cursor im Dataset verändern wird. Da das Dataset noch mit anderen visuellen Komponenten verbunden ist, oder warum auch immer, möchte ich den Cursor aber beibehalten. Also mache ich oft folgendes:


Delphi-Quellcode:
procedure TuIrgendWas;
var
  lBookmark : TArray<Byte>;
begin
  lBookmark := Dataset.Bookmark;
  Dataset.DisableControls;
  try
    { tu hier irgendwas, z.B. }
    Dataset.First;
    while not Dataset.Eof do
    begin
      { z.B. Feld in Datensatz aktualsisieren }
      Dataset.Edit;
      Dataset.FieldByName('markiert').AsInteger := 1;
      Dataset.Post;
      Dataset.Next;
    end;
  finally
    Dataset.Bookmark := lBookmark;
    Dataset.EnableControls;
  end;
end;
Das allgemeine Muster ist also:

Delphi-Quellcode:
var
  lBookmark : TArray<Byte>;
begin
  lBookmark := Dataset.Bookmark;
  Dataset.DisableControls;
  try
    { tu hier irgendwas}
  finally
    Dataset.Bookmark := lBookmark;
    Dataset.EnableControls;
  end;
Meistens ist das dann auch schon alles in der jeweiligen Prozedur. Ich suchte also eine Möglichkeit, den Rahmen um die eigentliche Arbeit schöner zu machen. Dabei bin ich auf folgende Lösung gekommen:

Ich habe irgendwo ein Interface definiert, das ein Objekt repräsentiert, das sich beim Erzeugen sowohl das Bookmark als auch das Dataset merkt und DisableControls aufruft. Wenn man danach eh die Procedure verläßt, wird auch das Interface wieder freigegeben und dabei dann der Cursor/das Bookmark zurückgesetzt und EnableControls aufgerufen. Hier eine kleine Unit mit Interface und Classe:

Delphi-Quellcode:
unit uIntfTest;

interface

uses
  Data.DB;

type
  IDBTool = interface(IInterface)
    ['{D924218E-DF15-486F-9322-A989DEF76B50}']
  end;

  TDBTool = class(TInterfacedObject, IDBTool)
  private
    FBookmark: TArray<byte>;
    FDataSet: TDataSet;
    procedure BeginUpdate;
    procedure EndUpdate;
  public
    constructor Create(const mDataSet: TDataSet);
    destructor Destroy; override;
  end;

function BookmarkAndDisable(const mDataset: TDataSet): IDBTool;

implementation

function BookmarkAndDisable(const mDataset: TDataSet): IDBTool;
begin
  Result := TDBTool.Create(mDataset);
end;

constructor TDBTool.Create(const mDataSet: TDataSet);
begin
  inherited Create;
  FDataSet := mDataSet;
  BeginUpdate;
end;

destructor TDBTool.Destroy;
begin
  EndUpdate;
  inherited;
end;

procedure TDBTool.BeginUpdate;
begin
  FBookmark := FDataSet.Bookmark;
  FDataSet.EnableControls;
end;

procedure TDBTool.EndUpdate;
begin
  FDataSet.Bookmark := FBookmark;
  FDataSet.EnableControls;
end;

end.
Nun kann man den obigen Code so abkürzen:

Delphi-Quellcode:
procedure TuIrgendWas;
begin
  BookmarkAndDisable(Dataset);
  { tu hier irgendwas }
end;
Delphi kümmert sich beim Freigeben des Interfaces, also am Ende der Prozedur automatisch um das Zurücksetzen des Bookmarks und die Control-Aktualisierung. Wenn man es früher braucht, müsste man doch mit einer lokalen Variablen arbeiten:

Delphi-Quellcode:
procedure TuIrgendWas;
var
  lIntf: IDBTool;
begin
  lIntf := BookmarkAndDisable(Dataset);
  { tu hier irgendwas }
  lIntf := nil;
  { tu nochmal was }
end;

Was meint ihr? Ist das eine brauchbare Lösung? Gibt es irgendwelche Pferdefüße?
Harald Schmid
  Mit Zitat antworten Zitat
Benutzerbild von stahli
stahli

Registriert seit: 26. Nov 2003
Ort: Halle/Saale
4.343 Beiträge
 
Delphi 11 Alexandria
 
#2

AW: Bookmark and DisableControls - ein kleiner Trick mit Interfaces

  Alt 1. Feb 2017, 15:30
Das Interface so einzusetzen sollte m.E. in Ordnung gehen.
Du musst halt darauf achten, keine weitere Referenz auf dieses Interface zu definieren, da dieses sonst nicht freigegeben wird.

Generell könnte man noch überlegen, solche nebenläufigen Datenänderungen direkt über ein SQL-Statement durchzuführen. Dann hätte das keine Auswirkungen auf den DB-Cursor.
Stahli
http://www.StahliSoft.de
---
"Jetzt muss ich seh´n, dass ich kein Denkfehler mach...!?" Dittsche (2004)
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.452 Beiträge
 
Delphi 12 Athens
 
#3

AW: Bookmark and DisableControls - ein kleiner Trick mit Interfaces

  Alt 1. Feb 2017, 15:39
In BeginUpdate sollte besser DisableControls verwendet werden.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
hschmid67

Registriert seit: 2. Jul 2012
Ort: Weilheim i. Obb.
71 Beiträge
 
Delphi 12 Athens
 
#4

AW: Bookmark and DisableControls - ein kleiner Trick mit Interfaces

  Alt 1. Feb 2017, 16:03
@Uwe Rabe: Vielen Dank - das ist natürlich ein Fehler

Delphi-Quellcode:
procedure TDBTool.BeginUpdate;
begin
  FBookmark := FDataSet.Bookmark;
  FDataSet.DisableControls;
end;
Harald Schmid
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
6.158 Beiträge
 
Delphi 10 Seattle Enterprise
 
#5

AW: Bookmark and DisableControls - ein kleiner Trick mit Interfaces

  Alt 1. Feb 2017, 16:19
Wenn du wirklich eine Meinung möchtest:

Es ist zwar spaßig, mittels ARC Dinge auszulösen (wie z.B. hier beim TDataSet). Aber abseits von Smart Pointern finde ich das persönlich eher kontraproduktiv.

Angenommen ich bin neu bei euch und sehe deinen Code zum ersten mal. Beim
Delphi-Quellcode:
Dataset.DisableControls();
   try
     { tu hier irgendwas}
   finally
     Dataset.EnableControls;
   end;
-Muster ist auf den ersten Blick alles klar.

Im Fall von
Delphi-Quellcode:
procedure TuIrgendWas;
begin
   BookmarkAndDisable(Dataset);
   { tu hier irgendwas }
end;
sparen wir zwar zwei Zeilen, aber es ist auf den ersten Blick überhaupt nicht ersichtlich was im Hintergrund wirklich passiert. Wenn man den Namen gut wählt sollte das zwar kein Problem sein, aber in anderen Fällen wird das vielleicht doch mal wichtig.

Beim Refactoring sehe ich bei so etwas auch eine Fehlerquelle (diskutiert vor etwas längerer Zeit): http://www.delphipraxis.net/180596-h...ml#post1260998. Bzw. macht es Refactoring unmöglich oder deutlich arbeitsaufwändiger.


Es gibt Fälle wo so etwas eine tolle Sache (mir fallen spontan nur Smart Pointer ein), aber dieser hier gehört mMn nicht dazu - Dafür ist der bestehende Code mit dem try..finally viel zu eindeutig und gut.

Geändert von Der schöne Günther ( 1. Feb 2017 um 16:23 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
4.629 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#6

AW: Bookmark and DisableControls - ein kleiner Trick mit Interfaces

  Alt 1. Feb 2017, 17:27
Sehe ich ähnlich wie Günther. Du hättest wahrscheinlich deine Freude mit C++, da dort das RAII Prinzip zum Einsatz kommt. Solche "Guards" sind da ganz normal. Ich persönlich finde es aber auch ziemlich unübersichtlich, wenn der "finally" Teil vor dem "eigentlichen Code" steht.

Wenn du dir die immer gleichen try..finally Blöcke sparen willst, könnte auch eine anonyme Prozedur ganz interessant sein:
Delphi-Quellcode:
type
  TMyAnonProc = reference to procedure(const Dataset: TDataset);

  TDatasetHelper = record
  public
    class procedure MyProcedure(const Dataset: TDataset; Proc: TMyAnonProc); static;
  end;

{ TDatasetHelper }

class procedure TDatasetHelper.MyProcedure(const Dataset: TDataset; Proc: TMyAnonProc);
var
  lBookmark : TArray<Byte>;
begin
  lBookmark := Dataset.Bookmark;
  Dataset.DisableControls;
  try
    Proc(Dataset);
  finally
    Dataset.Bookmark := lBookmark;
    Dataset.EnableControls;
  end;
end;
Aufruf dann so:
Delphi-Quellcode:
TDatasetHelper.MyProcedure(Dataset, procedure(const Dataset: TDataset)
  begin
    // do something
  end);
Projekte:
- GitHub (Profil, zyantific)
- zYan Disassembler Engine ( Zydis Online, Zydis GitHub)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.062 Beiträge
 
Delphi 12 Athens
 
#7

AW: Bookmark and DisableControls - ein kleiner Trick mit Interfaces

  Alt 1. Feb 2017, 17:55
Pssst, per Class-Helper als Funktion and TDataSet hängen, anstatt als irgendwo rumliegende eigenständige Funktion.
So hat man auch mehr Spaß am CodeInsigt/CodeVervollständigung.

Und nein, man kann sich auch das Interface speichern, um schon vor Prozedurende das Freizugeben.

Also das läuft ja bis zum END.
Delphi-Quellcode:
begin
  DataSet.BookmarkAndDisable;
  ...machwas
end;
Aber hier ist vorher Schluss.
Delphi-Quellcode:
var
  Bookmark: IDBTool; // oder IInterface
begin
  Bookmark := DataSet.BookmarkAndDisable;
  try
    ...machwas
  finally
    Bookmark := nil; // alternativ kann man auch ein Bookmark.EnableBookmark; anbieten
  end;
  ...machnochwas
end;
Da wir hier ein Interface haben, können wir das Try-Finally auch weglassen, denn Delphi baut implizit ein Try-Finally für solche lokalen Variablen ein, um sie freizugeben/finalisieren.
Delphi-Quellcode:
var
  Bookmark: IDBTool; // oder IInterface
begin
  Bookmark := DataSet.BookmarkAndDisable;
  ...machwas
  Bookmark := nil;
  ...machnochwas
end;
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.

Geändert von himitsu ( 1. Feb 2017 um 17:57 Uhr)
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
6.158 Beiträge
 
Delphi 10 Seattle Enterprise
 
#8

AW: Bookmark and DisableControls - ein kleiner Trick mit Interfaces

  Alt 1. Feb 2017, 17:59
Bookmark := nil;
Tut also genau das Gegenteil vom dem was es sagt: Es stellt ein Bookmark auf einem DataSet wieder her. Intuitiv ist das nicht.

Mir ist die (potentielle) Verwirrung die zwei gesparten Zeilen echt nicht wert.
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.452 Beiträge
 
Delphi 12 Athens
 
#9

AW: Bookmark and DisableControls - ein kleiner Trick mit Interfaces

  Alt 1. Feb 2017, 18:05
Tut also genau das Gegenteil vom dem was es sagt: Es stellt ein Bookmark auf einem DataSet wieder her. Intuitiv ist das nicht.
Eventuell kann man das auch nach dem Muster von TRecall aufbauen - mit anderer Implementierung halt.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
6.158 Beiträge
 
Delphi 10 Seattle Enterprise
 
#10

AW: Bookmark and DisableControls - ein kleiner Trick mit Interfaces

  Alt 1. Feb 2017, 18:07
Wieder was neues kennengelernt, danke!
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      

 

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 05:22 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