Laden...

Quasi-Modaler Dialog entwerfen

Erstellt von Turmoil vor 15 Jahren Letzter Beitrag vor 15 Jahren 2.513 Views
T
Turmoil Themenstarter:in
60 Beiträge seit 2008
vor 15 Jahren
Quasi-Modaler Dialog entwerfen

Ich möchte eine Basisklasse für (Dialoge) Forms erstellen, die Quasi-Modal angezeigt werden. Die Schaltflächen für das Schließen (DialogResult) liegen auf dem Aufrufer. Dieser sollte aber für alle anderen Aktivitäten gesperrt sein.
Der Anwendungsentwickler soll wie gewohnt schreiben können (o.ä.)


if (SeinDialog.ShowQuasiDialog() == DialogResult.OK) 
{
  ...
}

Nun meine Probleme:

  1. Wenn ich Form.ShowDialog verwende kann ich die Schaltflächen zum Schließen nicht beim Aufrufer hinterlassen.
  2. Wenn ich es Eventgesteuert zu lösen versuche, dann geht die Bedienerfreundlichkeit (für den Anwendungsentwickler) verloren. Es müsssen dann mind. 2 Stellen richtig überschrieben werden.

Mit Threads habe ich auch schon experimentiert, aber irgendwie klappt das nicht.

Hat jemend eine Idee?

Gruß Turmoil

49.485 Beiträge seit 2005
vor 15 Jahren

Hallo Turmoil,

sei nicht böse, aber ich finde das Konzept ziemlich ungünstig. Ich denke die Lösung wird sein, das Konzept zu ändern, nicht eine Antwort auf die genannten Fragen zu finden.

Die Schaltflächen für das Schließen (DialogResult) liegen auf dem Aufrufer.

Warum soll das so sein?

herbivore

Gelöschter Account
vor 15 Jahren

Also du willst quasi eine Art Child Window verstehe ich das richtig.
Das Fenster soll übergeblendet sein aber nicht modal.
Probier mal das Fenster als Child zu setzen. ( SetParent mit der WinApi z.B.)
Ansonsten gebe ich Hörbi aber recht, so sollte man's nicht machen.

49.485 Beiträge seit 2005
vor 15 Jahren

Hallo Sebastian.Lange,

Das Fenster soll übergeblendet sein aber nicht modal.

doch das Fenster soll (im Wesentlichen) schon modal sen ... mit Ausnahme der Schaltflächen für das Schließen.

Probier mal das Fenster als Child zu setzen.

Dafür braucht man nicht Win32. Das geht auch in .NET direkt: Form.Owner.

Ansonsten gebe ich Hörbi aber recht, so sollte man's nicht machen.

eben 😃 Deshalb nochmal meine Frage an Turmoil: Warum soll das so sein?

herbivore

T
Turmoil Themenstarter:in
60 Beiträge seit 2008
vor 15 Jahren

Hallo zusammen,

unsere Anwendung(en) laufen auf NC-gesteuerten Maschinen ohne Mausbedienung. Siemens ist da das Maß, an dem wir gemessen werden.

Das Schließen von Forms Dialogen etc. und die gesamte Programmsteuerung soll über Softkeys bwz. F-Tasten geschehen (siehe Bild im Anhang). Deshalb versuche ich mich gerade an eineme Basis-Dialog mit Knöpgen zum Schließen auf dem Hauptform, welches auch die anderen Ereignisse weiterleitet.

Gruß Turmoil

Gelöschter Account
vor 15 Jahren

Dann lag ich ja doch nicht so falsch.. und irgendwie doch.

Du könntest evtl. das KeyEvent das modalen Dialogs ableiten
und dann das Event samt Taste und sich selbst als Parameter an eine Default Verabeitung deiner Applikation schicken.

Natürlich musst Du noch einiges mehr tun, die Dialoge verarbeiten, speichern oder tun ja sonst irgendwas. Verdonnere z.b. deine Dialoge via Interface dazu eine Apply und eine Cancel Methode zu implementieren, diese könnte die Default verarbeitung aufrufen wenn sie meint die taste stimmt.

Naja halt irgendwie so..

Gruss!
Sebastian

T
Turmoil Themenstarter:in
60 Beiträge seit 2008
vor 15 Jahren

Das KeyEvent ist nicht das Problem. Dies habe ich mittels Frame-/ClientForm Beziehung schon gelöst. Events werden dabei mittels KeyPress oder mittels Button-Click ausgelöst.

Mein Problem ist das Drücken bzw. Enabled setzen der Knöpfe auf dem Frame- bzw. OwnerForm des Dialogs.

Das Anzeigen des Dialogs sollte sich wie eine statische Klassenfunktion verhalten (öffnen und auf schließen warten vgl. MessageBox.Show() oder Form.ShowDiaog()).

Gruß Turmoil

5.299 Beiträge seit 2008
vor 15 Jahren

Was ist eine NC-gesteuerten Maschine?

Ansonsten vllt Menüs greifen, und jedem Menu-Item einen Accessor-Key verpassen.
Außerdem ShortCuts.
Die ShortCut-Accessoren auch im MenuItem anzeigen (ShortCutKeyDisplayString).

Jedenfalls nicht das Gui vollballern mit Knöppen, auf die man nicht klicksen kann.

Das Menu-Konzept bietet halt die Möglichkeit, beliebig viele Knöppe unterzubringen, ohne beliebig viel Platz wegzunehmen.
Außerdem ist alles beschriftet und sinnvoll strukturiert.

ShortCuts lernen sich mit der Zeit dann von selbst.

Der frühe Apfel fängt den Wurm.

T
Turmoil Themenstarter:in
60 Beiträge seit 2008
vor 15 Jahren

Was ist eine NC-gesteuerten Maschine?

siehe:
Wikipedia -CNC
Siemens-Pressemitteilungen

Die Knöpfe auf dem Frameform der Anwendung sind sozusagen die immer angezeigten Menüs (siehe Bild weiter oben). Es werden dann je nach Clientform Events inklusive Beschriftung an-/abgemeldet.

Ich würde nun gerne Dialogfunktionalität dort hinterlassen.

Gruß Turmoil

49.485 Beiträge seit 2005
vor 15 Jahren

Hallo Turmoil,

wenn die Knöpfe übergeordnet sind, warum packst du sie dann nicht in ein extra Fenster? Dann machst du den Dialog modal zum Hauptfenster und kannst, weil die Knöpfe in einem unabhängigen Fenster sind, diese weiter bedienen.

herbivore

T
Turmoil Themenstarter:in
60 Beiträge seit 2008
vor 15 Jahren

Hallo herbivore,

wenn ich das From mit ShowDialog() öffne, dann läßt sich die ganze Applikation nicht mehr bedienen. Egal welches Form ich zuvor anzeige.

Oder wie war das gemeint?

Dann machst du den Dialog modal zum Hauptfenster

Gruß Turmoil

5.299 Beiträge seit 2008
vor 15 Jahren

Ich dachte, das sei der gewünschte Effekt, so habich jedenfalls dein ersten Post verstanden.

Die Schaltflächen für das Schließen (DialogResult) liegen auf dem Aufrufer. Dieser sollte aber für alle anderen Aktivitäten gesperrt sein.

Ich würde bei Buttons, die mangels Maus nicht klickbar sind, auch nicht von Buttons reden (oder solche nehmen) sondern das sind wohl eher Labels.

Und Steuerung ist eben Tastatur.

Wie gesagt, ein Menu ist auch Tastatur-gesteuert, und viel logischer aufgebaut, und setzt sich als Steuerung auch klar ab von üblichen Tastatur-Eingaben (aber vllt. gibts da ja auch keine).

Aber krass unlogisch und konträr zu allen Windows-Anwendungen, die ich kenne, ist die Idee, den Schließen-Button eines Forms ausserhalb desselben zu positionieren.
Sonen Button (oder ein dahingehend beschriftetes Label) tätich so verstehen, dasses zum Schließen der Hauptanwendung führt.

Der frühe Apfel fängt den Wurm.

A
764 Beiträge seit 2007
vor 15 Jahren
  1. Wenn ich es Eventgesteuert zu lösen versuche, dann geht die Bedienerfreundlichkeit (für den Anwendungsentwickler) verloren. Es müsssen dann mind. 2 Stellen richtig überschrieben werden.

Das wäre aber ihmo der richtige Weg. Schliesslich hast du ja auch andere Vorraussetzungen als bei der normalen Dialogbox.

Aber ne Möglichkeit wäre vllt, die entsprechenden Methoden öffentlich zu machen und mit den Buttons dann darauf zu verweisen.

btnOk.Click += dialogBox.BtnOk_Clicked(...);
49.485 Beiträge seit 2005
vor 15 Jahren

Hallo Turmoil,

wenn ich das From mit ShowDialog() öffne, dann läßt sich die ganze Applikation nicht mehr bedienen.

das stimmt nicht ganz. Es lässt sich kein Fenster mehr bedienen, dass in dem gleichen Thread läuft wie der Dialog. Nun bin ich zwar im Allgemeinen ein Verfechter von: "eine Anwendung soll nur einen GUI-Thread haben". Aber besondere Situationen erfordern besondere Maßnahmen. Wenn du also das extra Fenster in einem anderen Thread laufen lässt (der dann natürlich sein eigenes Application.Run haben muss), gehts so wie ich vorgeschlagen habe.

herbivore

T
Turmoil Themenstarter:in
60 Beiträge seit 2008
vor 15 Jahren

Hallo Zusmmen.

@ErfinderDesRades:
Bei unseren Anwendungen handelt es sich nicht um klassische Windows-Forms-Applikationen. Ich habe Steuer-Knöpfe im Hauptform platziert, die mit der Maus gedückt werden können (ist auf unseren NC-Maschinen aber nicht die Regel, eher am PC bei der Entwicklung), deren ClickEvent aber ebenso über F-Tasten ausgelöst werden (idR. wird dies so auf den Maschinen passieren).

@Alf Ator:
Dies (btnOk.Click += Event(...)) habe ich so ähnlich schon realisiert. Ob eventgesteuert der richtige Weg ist, kann ich so nicht sagen. Mein Chef und die Anwendungsentwickler hätten es bei einem modalen Dialog einfacher.

@herbivore:
Ich werde es mal mit einem extra Thread und Application.Run versuchen. Gibts da irgendwo ein Bsp.? Ich habe schon etwas gestöbert, aber noch nicht den richtigen Beitrag gefunden.

Gruß Turmoil

49.485 Beiträge seit 2005
vor 15 Jahren

Hallo Turmoil,

was brauchst du da für ein Beispiel? Thread starten und Application.Run mit new MyForm als Parameter aufrufen. Mehr ist es doch nicht.

herbivore

T
Turmoil Themenstarter:in
60 Beiträge seit 2008
vor 15 Jahren

Hallo herbivore.


tmpThread = new Thread(new ThreadStart(F.Show));
tmpThread.Start();
Application.Run(F);

Löst bei Application.Run(F) die nachfolgende Fehlermeldung

Starting a second message loop on a single thread is not a valid operation. Use Form.ShowDialog instead.

und ohne Application.Run geht das Form sofort wieder zu.
Hab mit Threading noch wenig Erfahrung, sorry. Kleiner Tipp ?(

Gruß Turmoil

49.485 Beiträge seit 2005
vor 15 Jahren

Hallo Turmoil,

... in einem anderen Thread laufen lässt (der dann natürlich sein eigenes Application.Run haben muss) ...

herbivore

5.299 Beiträge seit 2008
vor 15 Jahren

Hallo Zusmmen.

@ErfinderDesRades:
Bei unseren Anwendungen handelt es sich nicht um klassische Windows-Forms-Applikationen. Ich habe Steuer-Knöpfe im Hauptform platziert, die mit der Maus gedückt werden können (ist auf unseren NC-Maschinen aber nicht die Regel, eher am PC bei der Entwicklung)

Ui, da musste aber aufpassen!

Sonst bastelstene prima Anwendung, die auf der Maschine dann nicht bedienbar ist.
Evtl jetzt erst recht keine Buttons nehmen.

Der frühe Apfel fängt den Wurm.

T
Turmoil Themenstarter:in
60 Beiträge seit 2008
vor 15 Jahren

Hallo herbivore.

ich habe einiges versucht aber dennoch funktioniert es nicht so wie erwartet (das Einkommentieren von Application.Run() hat m.E. keine Auswirkung).

Wenn ich die Knöpfe des FrameForms nicht ändere, dann geht das DialogForm auf und nach dem Schließen gehts auch weiter. Wenn ich aber mittels ThreadEventsAnmelden die Events des Dialogforms beim FrameForm anmelde, hängt sich mein GUI auf (wahrscheinlich häng mein GUI (FrameForm) auch ohne Anmelden der Dialog-Events).

Ich habe schon den Beitrag in den FAQ gelesen, leider widersprechen sich da einige Aussagen bzw. passen nicht auf den hier vorliegenden Fall.
Hier mein vereinfachter Quellcode:


class BFrameForm: Form
{
	.....
	private Type DialogFormType;
	private DialogResult DialogRes;
	private delegate void EventsAnmelden(List<ButtonEvent> EList); // Liste mit Delegaten für die Knöpfe
	private EventsAnmelden ThreadEventsAnmelden;

	private void DialogFormShowThread()
	{
		if (DialogFormType != null)
		{
			Form F = (Form)Activator.CreateInstance(DialogFormType);
			if (F is BDialogForm)
			{
				this.Invoke(this.ThreadEventsAnmelden, new Object[] {(F as BDialogForm).EventList });
			}
			F.TopMost = true;
			//Application.Run(F);
			DialogRes = F.ShowDialog();
		}
	}

	public DialogResult DialogFormShow(Type FormType)
	{
		if (FormType != null)
		{
			DialogFormType = FormType;

			PnlBackground.Enabled = false;

			LoggingOffEvents(); // eigene Events von den Knöpfen abmelden

			this.ThreadEventsAnmelden = new EventsAnmelden(this.LoggingOnEvents);

			// neuen Thread mit Methode die den Dialog anzeigt starten
			Thread tmpThread = new Thread(new ThreadStart(DialogFormShowThread));
			tmpThread.Start();

			while (tmpThread.IsAlive)
			{
				Thread.Sleep(100);
			}

			this.OwnEventsAnmelden = null;

			PnlBackground.Enabled = true;

			LoggingOffEvents();			// Events von den Knöpfen abmelden
			LoggingOnEvents(OwnEventList); // eigene Events von den Knöpfen anmelden

			return DialogRes;
		}
		else
		{ return DialogResult.Cancel; }
	}
	....
}

Wo liegt denn da der Hase begraben?

Gruß Turmoil

49.485 Beiträge seit 2005
vor 15 Jahren

Hallo Turmoil,

sorry, ich verstehe nicht, was du da treibst. Starte einen Thread. Erzeuge darin das Form mit den Knöpfen. Rufe mit diesem Form als Parameter Application.Run auf. Das sind drei Zeilen Code. Mehr ist es nicht. Alles andere machst du wie vorher.

Das einzige wo du aufpassen musst, ist das Events, die von den Knöpfen gefeuert werden, jetzt in dem neu erzeugen Thread laufen. Wenn du aus den EventHandlern auf Forms im eigentlichen GUI-Thread aufrufen willst, musst du also ganz normal [FAQ] Controls von Thread aktualisieren lassen (Control.Invoke) beachten.

Ich habe schon den Beitrag in den FAQ gelesen, leider widersprechen sich da einige Aussagen

Glaube ich erstmal nicht. Welche?

herbivore

T
Turmoil Themenstarter:in
60 Beiträge seit 2008
vor 15 Jahren

Hallo herbivore,

Widersprüche:

  • nur kurze Anweisungen in den 2. Thread auslagern
  • nur einen GUI-Thread

Das Form mit den Knöpfen ist das Hauptform der Applikation. Ich habe den Programmstart s.u. umgestellt, aber die Knöpfe funktionieren trotzdem nicht. Das sieht aber irgendwie komisch aus, oder


static class Program
{
	/// <summary> Der Haupteinstiegspunkt für die Anwendung. </summary>
	static void Main()
	{
		Thread MainThread = null;
		if (MainThread != null)
		{
			MainThread = new Thread(new ThreadStart(Main));
			MainThread.Start();			
		}
		
		Application.EnableVisualStyles();
		Application.SetCompatibleTextRenderingDefault(false);
		TestFrameForm f = new TestFrameForm();
		f.FormInit();
		Application.Run(f);
		f.FormDone();
	}
}

Ich glaub ich lass es. Ich werde es Eventgesteuert lösen.
Danke an Alle für die Bemühungen.

Gruß Turmoil

49.485 Beiträge seit 2005
vor 15 Jahren

Hallo Turmoil,

ich habe ja schon oben gesagt:

Nun bin ich zwar im Allgemeinen ein Verfechter von: "eine Anwendung soll nur einen GUI-Thread haben". Aber besondere Situationen erfordern besondere Maßnahmen.

Insofern besteht kein Widerspruch, sondern es liegt hier nur eine Ausnahme vor.

Außerdem steht in der FAQ nicht, dass kurze Anweisungen in den zweiten Thread ausgelagert werden sollen, sondern im Gegenteil steht das da für langlaufende Aktionen.

Es ist auch kein Widerspruch, dass es nur einen GUI-Thread geben, aber trotzdem einen zweiten Worker-Thread für langlaufende Aktionen geben soll. Denn GUI-Thread ist gerade ungleich Worker-Thread.

Das Form mit den Knöpfen ist das Hauptform der Applikation.

Und mein Vorschlag war, die Knöpfe in ein extra Form (also ein drittes Form) auszulagern. Wenn die Knöpfe weiterhin im Hauptform liegen funktioniert der Vorschlag mit dem zweiten Thread natürlich nicht.

herbivore

643 Beiträge seit 2006
vor 15 Jahren

Application.Run in einen neuen Thread


			new Thread(new ThreadStart(delegate()
			{

				Form form = new Form();
				Application.Run(form);

			})).Start();

Die Eingaben würde ich nicht über die Forms nehmen sondern über einen Hook. Diese werden dan an eine Klasse weitergereicht die diese verarbeitet.

946 Beiträge seit 2008
vor 15 Jahren

Oder über Linq:

new Thread(() =>
{
    Form form = new Form();
    Application.Run(form);

}).Start();