![]() |
Actions verwenden - Pre- und Post-Action
Hallo,
bin mir nicht sicher, ob hier der richtige Platz ist, darum bitte an die Mods, ggf. verschieben. Ich habe folgendes Problem: Es geht um eine Anwendung mit mehreren Fenstern. Jedes Fenster hat ein Mainmenu und Buttons. Den Menü-Einträgen und Buttons ist größtenteils eine Action zugewiesen. Die TActionlist befindet sich in einem separaten Datenmodul, das von allen Fenstern verwendet wird. Soweit so gut. Nun muss ich aber manchmal wenn eine Action ausgeführt wird, vorher und nachher am Formular Änderungen vornehmen, z.B. Button's disablen, damit die Funktion/Action nicht rekursiv aufgerufen wird. Ich müsste also praktisch vor und nach dem Ausführen der Action etwas ausführen. Hat man daran nicht gedacht? Oder geht das, und ich seh den Wald vor Bäumen nicht? |
AW: Actions verwenden - Pre- und Post-Action
Zitat:
Also stellt sich zunächst die Frage, warum du während des Events ünerhaupt einen Button disablen willst. Vielleicht, weil der Event zulange braucht under Benutzer aus Frust immer wieder auf den Button klickt? Je nach Anwendungsfall gibt es da verschiedene Ansätze. Ein Wunsch nach einem Pre- und Post-Action-Event ist m.W. bisher noch nicht aufgetaucht. |
AW: Actions verwenden - Pre- und Post-Action
Hallo mm1256,
wenn du meinst das während des Events Componenteneigenschaften geändert werden, und dabei werden neue Actions getriggert, so das etwas rekursiv oder anders falsch läuft. Man kann ja die OnChange Events vor solchen Veränderungen kurz abklemmen (OnChange := nil), Werte, z.B. Text ändern, und danach wieder anklemmen (OnChange := oldEvent;). Wenn das nur ein einzelnes Problem betrifft. Aber vielleicht wäre es sauberer wenn du vielleicht ein MultiEvent-System von ![]() Rollo |
AW: Actions verwenden - Pre- und Post-Action
Siehe mein Tutorial
![]()
Delphi-Quellcode:
Alle Buttons, die mit dieser Action verbunden sind, folgen der Enabled Eigenschaft.
procedure TFoo.BarActionExecute( Sender: TObject );
begin TAction(Sender).Enabled := False; FService.DoSomething( procedure ( AResult: TBar; AException: Exception ) begin // Verarbeitung der Rückgabe TAction(Sender).Enabled := true; end ); end; |
AW: Actions verwenden - Pre- und Post-Action
Hallo,
erst mal vielen Dank für eure Antworten. Der Tipp von Sir Rufo löst das Problem teilweise, d.h. bei einigen Actions passt das prima. :thumb: Bei anderen Actions die gegeneinander verriegelt werden müssen und länger dauern können (z.B. alle Aktionen die Änderungen am Datenbestand vornehmen wie Daten-Import, Daten-Export...) wird es problematischer. Ich hab mich nun dazu entschlossen, die Actions im Public-Bereich der TActions zu deklarieren und entsprechend zu verwenden. Erscheint mir momentan der brauchbarste Kompromiss zu sein. Das ursächliche Problem hier ist - wie Uwe schon richtig vermutet hat - das "Verbotene". In dem Fall bei der Fortschritt-Anzeige. |
AW: Actions verwenden - Pre- und Post-Action
Hmmm, jede Action hat ein
Delphi-Quellcode:
Event und dort kann man z.B. die Eigenschaften der Action verändern (dafür ist der Event da).
OnUpdate
Und genau dort stellt man dann die Abhängigkeiten zwischen den Actions her. Einfach ein paar Flags die beim Starten einer Action gesetzt werden und dann im
Delphi-Quellcode:
die Enabled Eigenschaft der jeweiligen Action setzen.
OnUpdate
|
AW: Actions verwenden - Pre- und Post-Action
@SirRufo: Das haut leider nicht hin, denn "OnUpdate" wird bereits gefeuert, wenn das Menü gezeichnet wird.
TActionList.OnExecute wäre als Pre-Event geeignet, die infrage kommenden Actions zu disablen, aber das ist mir auch zu umständlich zu implementieren. Aber, ich glaub ich hab die Lösung. Der Grundgedanke ist, in der Action die erforderlichen Actions zu disablen, und nach Ausführung der Action diese wieder zu enablen. Code-Auszug:
Delphi-Quellcode:
Ein bischen Q&D aber so funktioniert's erst mal. Verbesserungsvorschläge sind gerne willkommen.
type
TActionArray = array of TAction; TActions = class(TDataModule) MyActionList: TActionList; acImport: TAction; acExport: TAction; . . . public { Public-Deklarationen } procedure Actions_Disable(aActionsToDisable: TActionArray); procedure Actions_Enable; end; implementation procedure TActions.Actions_Disable(aActionsToDisable: TActionArray); var i, Lst: integer; begin for i := 0 to Pred(Actions.MyActionList.ActionCount) do begin for Lst := Low(aActionsToDisable) to High(aActionsToDisable) do begin if Actions.MyActionList.Actions[i] = aActionsToDisable[Lst] then begin if Actions.MyActionList.Actions[i].Enabled then begin // Actions die bereits disabled sind ausschließen Actions.MyActionList.Actions[i].Tag := 1; // Flag setzen, dass die Action disabled wurde Actions.MyActionList.Actions[i].Enabled := false; end; end; end; end; end; procedure TActions.Actions_Enable; var i: integer; begin for i := 0 to Pred(Actions.MyActionList.ActionCount) do begin if Actions.MyActionList.Actions[i].Tag > 0 then begin Actions.MyActionList.Tag := 0; Actions.MyActionList.Actions[i].Enabled := true; end; end; end; procedure TActions.acImportExecute(Sender: TObject); begin Actions_Disable([acImport,acExport]); try // Export durchführen finally Actions_Enable; end; end; |
AW: Actions verwenden - Pre- und Post-Action
Du machst dir einfach das Leben zu schwer ...
Delphi-Quellcode:
Das
procedure TFoo.BarActionUpdate(Sender:Tobject);
begin TAction(Sender).Enabled = not FBarRunning; end; procedure TFoo.BarActionExecute(Sender:TAction); begin BarRunning := True; FService.DoBar( procedure (AResult:TBar; AException:Exception) begin // ... BarRunning := False; end ); end;
Delphi-Quellcode:
wird immer wieder ausgelöst und hat als Hauptaufgabe, den Status einer Action zu setzen. Also genau das, was du brauchst.
OnUpdate
Im
Delphi-Quellcode:
sollst du NICHT irgendeine Aktion ausführen, sondern NUR den Status einer Action setzen.
OnUpdate
Wenn du dich jetzt auf einige Flags einigen kannst, dann sieht so eine
Delphi-Quellcode:
Methode z.B. auch so aus:
OnUpdate
Delphi-Quellcode:
procedure TFoo.SomeAction(Sender:TObject);
begin TAction(Sender).Enabled := ( not BarRunning and FooRunning ) or FooBarRunning; end; |
AW: Actions verwenden - Pre- und Post-Action
Das hab ich schon kapiert (dass ich im OnUpdate nur die Flags setzen soll) aber da bin ich auf ein paar Probleme bzw. Nachteile gestoßen:
- Neue Action bedeutet manchmal auch neues Flag, da kommt eine ansehnliche Anzahl an Flags zusammen. Wobei die Anzahl nicht das Problem ist, sondern die Lesbarkeit des daraus resultierenden Codes. - Wenn eine Action (sprich ein Menüpunkt oder ein Button) durch etwas Anderes Disabled wurde (z.B. die Benutzerrechte) dann muss ich das bei den Flags zusätzlich mit berücksichtigen. Sonst schalten mir die Flags wieder Menüpunkte ein, die vorher disabled waren. Das wird langfristig gesehen schwer zu pflegender Code. Hinzu kommt, die Benutzerrechte und die "Verriegelung" der Actions untereinander sind zwei Schichten, die ich nicht miteinander vermischen möchte. Bei der aktuellen Variante muss ich mir lediglich bei der Ausführung der Action Gedanken machen, welche Actions disabled werden sollen
Code:
und das Enablen passiert automatisch. Dadurch wird übrigens nicht das Tag der Menü-Items/Buttons beeinflusst, d.h. ich kann deren Tag unabhängig davon weiter verwenden.
Actions_Disable([.....])
Ich werde es jetzt mal so weiter verfolgen. Vielleicht tauchen ja noch neue Probleme auf, und ich muss doch noch auf irgendwelche Flags zurückgreifen. |
AW: Actions verwenden - Pre- und Post-Action
Oh ja, die Benutzrechte sind ja sooo schwer da mit reinzubringen:
Delphi-Quellcode:
und auch noch total unübersichtlich ... :roll:
TAction(Sender).Enabled :=
CurrentUser.HasRight( 'Foo' ) and not FooRunning; Mit den Flags meine ich nicht die Eigenschaften der Actions, sondern ob irgendetwas aktiv gerade läuft. Die Eigenschaften der Actions setzt man dann im
Delphi-Quellcode:
und zwar abhängig von diesen Flags.
OnUpdate
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 08:20 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz