Entwickler-Ecke

Basistechnologien - Form schließen


Talemantros - Mo 28.12.15 17:34
Titel: Form schließen
Hallo zusammen,
ich habe da mal wieder ein kleines Problem, welches ich leider nicht gelöst bekomme.
Wo ich noch Forms benutzt habe um Steuerelemente anzuzeigen war es kein Problem mit


C#-Quelltext
1:
this.close();                    


dieses zu schließen.

Nun zeige ich ja die Steuerelemte in einem UserControl an, welches geladen wird.
Wie kann ich einem Button nun sagen, dass er beim Klick das Form unter dem UserControl schließen soll?

Danke.

Viele Grüße


Ralf Jansen - Di 29.12.15 15:09

Da stellt sich die Frage wieso der Button auf einem UserControl liegt. Ein Button dessen Aufgabe das schließen der Form ist auf einem UserControl zu haben richt etwas nach Designfehler.

Wenn der Button da aus irgendeinem mir nicht ersichtlichen Grund hin muss dann würde ich vom UserControl ein entsprechendes Event veröffentlichen damit ich den passenden Code dann auf der Form ausführen kann. Also den Click Event des Button den entsprechenden Event des UserControls ausführen lassen damit dort das passende auf der Form ausgeführt werden kann.


Talemantros - Mi 30.12.15 17:09

Hey,
also aus meiner Sicht gab es dazu keinen Grund.
Ich dachte, dass wäre so, dass man auf der Form nichts mehr hat, da das UserControl ja mit Dock.Fill geladen wird und der Button dann nicht sichtbar ist?
Daher implizierte ich, dass auch der Schließen Button da hin gehört.

Gruß

EDIT:
bzw. wenn die Form sich selber schließen soll, nach bestimmten Aktivitäten in der UserControl müsste ich vermutlich wieder mit Events arbeiten?


C# - Mi 30.12.15 17:56

Tach,

quick and dirty kannst du das Fenster so schließen:

C#-Quelltext
1:
((Form)this.Parent).Close();                    


Aber wie Ralf bereits geschrieben hat, sollte ein UserControl nicht die Form manipulieren.


Ralf Jansen - Mi 30.12.15 18:57

Zitat:
Ich dachte, dass wäre so, dass man auf der Form nichts mehr hat, da das UserControl ja mit Dock.Fill geladen wird und der Button dann nicht sichtbar ist?


Du mußt das UserControl nicht direkt auf die Form werfen. Zum Beispiel wäre es ein leichtes die Form mit 2 Panel zu strukturieren. Ein Panel für die Buttons zum steuern der Form (mit Dock.Bottom) und ein 2.tes (mit Dock.Fill) um darauf dann wieder verschiedene UserControl platzieren zu können. Wenn du dann Dock.Fill des UserControls setzt füllt es ja nur die Fläche seines Parents also des Panels.

@C# Das der Parent eine Form ist wäre eher Zufall. Auf jedenfall wäre solcher Code unglücklich weil man das UserControl in seiner Nutzung soweit einschränkt das es nur funktioniert wenn man es direkt auf eine Form wirft. Quick and Dirty ist da schon mehr als eine Untertreibung ;)

Zitat:
bzw. wenn die Form sich selber schließen soll, nach bestimmten Aktivitäten in der UserControl müsste ich vermutlich wieder mit Events arbeiten?


Müssen musst du nicht. Ich würde es aber höchstwahrscheinlich als den richtigen Weg bezeichnen.


C# - Mi 30.12.15 21:17

@Ralf dann macht man einfach eine hierarchische Suche ala:

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
Control c = this.Parent;
while (c != null
{
  Form f = c as Form;
  if (f != null)
  {
    f.Close();
    break;
  }
  c = c.Parent;
}

:dance:


Talemantros - Mi 30.12.15 21:53

Schon mal danke euch beiden
Bisher habe ich erst einmal ein Event geschrieben und das ist ewig her

Da ich dies sicher nich öfter brauche würde ich mir dies gern genauer anschauen.
Auch die Idee mit den Panels werde ich aufnehmen.

Würdet ihr mir Hilfestellung geben mit dem Event?
Ich wüsste gerade nicht wie ich anfangen sollte.

Versuche mal das alte Event irgendwie zu nutzen.


Ralf Jansen - Mi 30.12.15 22:34

user profile iconC# hat folgendes geschrieben Zum zitierten Posting springen:

:dance:


Gratuliere du hast ungefähr FindForm [https://msdn.microsoft.com/de-de/library/system.windows.forms.control.findform(v=vs.110).aspx] nachimplementiert ;)


Talemantros - Mi 30.12.15 23:49

Leider finde ich keinen Anfang
Beim letzten hatte ich TextEventArgs verwendet, gibt's da jetzt ButtonEventArgs oder woher weiß ich wie ich da starte ?


Ralf Jansen - Do 31.12.15 00:11

Zitat:
Leider finde ich keinen Anfang


Für was? Wenn du keine speziellen EventArgs brauchst nimm einfach die EventArgs Klasse.


C# - Do 31.12.15 02:37

Also ich würde ein eigenes event für das UserControl erstellen. So etwas wie
public event EventHandler<DeineEventArgs> OnCloseRequest;


@Ralf
Homer-nein


Talemantros - Do 31.12.15 11:47

Guten Morgen,
es tut mir sehr leid, aber leider komme ich nicht klar.
Ich habe versucht, das einzige Event in meinem Tool noch mal zu verstehen und selbst das gelingt mir gerade nicht mehr.

Wenn ich im UserControl anfange:


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
        public event EventHandler<ButtonEventArgs> CloseRequest;

        protected virtual void OnCloseRequest(ButtonEventArgs e)
        {
            EventHandler<ButtonEventArgs> ev = CloseRequest;
            if (ev != null)
                ev(this, e);
        }


Vorausgesetzt, dass oben stehende würde stimmen müsste ich nach abarbeiten des UserControls, wenn es sich schließen soll dies aufrufen

C#-Quelltext
1:
OnCloseRequest();                    


Wie bzw. was muss ich den jetzt in der Form machen, damit diese weiß, wie sie das Event fängt und dann eine Aktion ausführt.

Danke

Gruß


Th69 - Do 31.12.15 12:34

So wie bei anderen Ereignisse aus: in deiner Form-Klasse abonnierst du das Event und in der aufgerufenen Eventmethode führst du dann die Aktion aus.

Auch bzgl. deiner anderen Frage Methode einer anderen Form [http://www.entwickler-ecke.de/viewtopic.php?t=114979] kann ich dich nur (wieder) auf meinen Artikel Kommunikation von 2 Forms [http://www.bitel.net/dghm1164/programming/Kommunikation_von_2_Forms.html] hinweisen.

Du scheinst Ereignisse noch nicht (richtig) verinnerlicht zu haben. Der Sinn besteht ja darin, daß die untergeordnete Klasse nicht die übergeordnete (andere) Klasse kennen muß, sondern einfach nur signalisiert: "hier ist etwas passiert und in den EventArgs stehen weitere Infos dazu". Was die andere Klasse (bzw. anderen Klassen) dann damit macht, ist der Klasse, welche das Ereignis wirft, dann völlig egal.
Erst im Gesamtzusammenhang ergibt sich dann der komplette Programmablauf (die Ereignisse und Methodenaufrufe anderer Klassen sind dann die Bindeglieder).


Talemantros - Do 31.12.15 14:55

Danke noch mal für die ausführliche Erläuterung.
Ich habe dies tatsächlich noch nicht richtig begriffen :-(

Ich bleib dran und versuche dass hier morgen mal anzugehen.

Edit:
Ich habe jetzt folgendes und es funktioniert.
Würde euch mal bitten zu gucken, ob es so gelassen werden kann.

Im UserControl habe ich folgendes deklariert

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
        public event EventHandler<ButtonEventArgs> CloseRequest;

        protected virtual void OnCloseRequest(ButtonEventArgs e)
        {
            EventHandler<ButtonEventArgs> ev = CloseRequest;
            if (ev != null)
                ev(this, e);
        }

        public class ButtonEventArgs : EventArgs
        {
            public ButtonEventArgs()
            {
            }
        }


Und rufe es wie folgt auf


C#-Quelltext
1:
                OnCloseRequest(new ButtonEventArgs());                    


Im Form selber habe ich


C#-Quelltext
1:
2:
3:
4:
5:
                    BarcodeNeuUserControl controlNeu = new BarcodeNeuUserControl(employee);
                    controlNeu.BarcodeText = barcodeText;
                    controlNeu.CloseRequest += CloseForm; // Das hier ist neu dazugekommen
                    controlNeu.Dock = DockStyle.Fill;
                    Controls.Add(controlNeu);


Und hiermit ist es abonniert

C#-Quelltext
1:
2:
3:
4:
        private void CloseForm(object sender, BarcodeNeuUserControl.ButtonEventArgs e)
        {
            this.Close();
        }


Danke fürs prüfen und im Allgemeinen für die Hilfe

Gruß


Ralf Jansen - Do 31.12.15 15:27

Sieht korrekt aus.

Der Sinn von ButtonEventArgs ergibt sich mir nicht (und was soll Button im Namen? Wenn schon CloseRequest dann würde ich das eher auch CloseRequestEventArgs nennen). Warum benutzt du nicht einfach EventArgs? Eine eigene Klasse brauchst du erst wenn du mit denn EventArgs auch Daten zum Auswerten im Event transportieren willst.


Th69 - Fr 01.01.16 17:24

Hallo Talemantros,

zuerst einmal "Frohes Neues Jahr".

Genauso meinte ich es (aber den Anmerkungen von Ralf stimme ich auch zu ;- )
Wichtig ist aber zu wissen und zu verstehen, wie man eigene EventArgs benutzt, wenn man sie denn wirklich braucht.


C# - Fr 01.01.16 17:50

Ein frohes Neues auch von mir.

Eigene EventArgs machen nur Sinn, wenn du zusätzliche Informationen bereitstellen willst. Angenommen du willst den Grund weitergeben, warum die Form geschlossen werden soll, dann machst du dir ein Enum mit den möglichen Gründen, z.B.:

C#-Quelltext
1:
2:
3:
4:
5:
6:
enum CloseReasons
{
    None,
    UserForced,
    ControlNeedsReload,
}


Um diesen Grund jetzt and deine subs weiterzuleiten, musst du eine eigene EventArgs-Klasse erstellen:

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
public class CloseEventArgs : EventArgs
{
    public CloseReason Reason {get; private set;}
    
    public CloseEventArgs(CloseReason reason)
    {
        Reason = reason;
    }
}


Dann wird dein Event so aussehen:

C#-Quelltext
1:
public event EventHandler<CoseEventArgs> CloseRequest;                    


Deine Helfermethode sieht dann so aus:

C#-Quelltext
1:
2:
3:
4:
protected virtual void OnCloseRequest(CloseEventArgs e)
{
    if (CloseRequest != null) CloseRequest(this, e);
}


In den subs kannst du dann die Infos verwenden:

C#-Quelltext
1:
2:
3:
4:
5:
private void CloseForm(object sender, CloseEventArgs e)
{
    if (e.Reason != CloseReason.None) this.Close();
    else MessageBox.Show("No given close reason.");
}




Wenn du keine zusätzlichen Infos weitergeben möchtest bei deinen Events, reicht die EventArgs-Klasse. Dein event sieht dann so aus:

C#-Quelltext
1:
public event EventHandler<EventArgs> CloseRequest;                    

oder etwas kürzer

C#-Quelltext
1:
public event EventHandler CloseRequest;                    


Auslösen tust du das Event dann mit:

C#-Quelltext
1:
OnCloseRequest(new EventArgs())                    

oder mit

C#-Quelltext
1:
OnCloseRequest(EventArgs.Empty)                    


Talemantros - Sa 02.01.16 14:03

Hallo zusammen und auch von mir ein "Frohes neues Jahr"
Danke für die weiteren Erläuterungen.
Ich habe diese eben noch mal bei mir umgesetzt.

Daraus ergibt sich jetzt noch eine Frage:
Im Moment abonniert ja die Form das Event, des UserControls.
Die Form selber ist eine Form die von der Hauptanwendung aus gestartet wurde.

Wenn ich jetzt wollte, dass das Hauptfenster der Anwendung dies abonniert wie wäre das dann?
Müsste dann die Form, die es aktuell abonniert wieder ein Event auslösen, welches von der Hauptanwendung gefangen wird?

Zum Beispiel bei einem MouseOver über ein Steuerelement soll in der Statusleiste der Hauptanwendung ein InfoText dazu stehen?

Vielen Dank

Gruß


Ralf Jansen - Sa 02.01.16 15:06

Ja und ein bisschen nein ;)

Ja wenn du tatsächlich die Anforderung hast eine reine Userinteraktion einer Form an eine andere weiterzuleiten wird meist ein Event der günstigste Weg sein.
Aber diese Art der Anforderung erscheint mir eher fragwürdig. Wenn sich Formen etwas teilen sind es eher Daten und in dem Fall wäre es eher so das das Model Events wirft das von den betroffenen Formen gefangen wird, die Formen würden dann untereinander nicht direkt kommunizieren. Unabhängigkeit der Einzelteile ist ein hohes gut in einer Anwendung gerade der UI daher ist es üblich das die UI Bestandteile untereinander so wenig wie möglich (eben nur da wo absolut nötig) miteinander direkt kommunizieren.

In deinem Beispiel mit dem MouseOver wäre wohl der Weg über eine Event ok. Wenn das aber ein übliches Problem dieser Anwendung ist (Dinge die irgendwo passieren sollen auf der Mainform visualisiert werden) dann würde ich über ein richtiges Anwendungspattern wie zum Beispiel einen Message Broker nachdenken. Also einen Service an den alle Formen/Controls einer Anwendung Nachrichten senden können, der Message Broker würde dann die Informationen aller Formen sammeln (loggen, priorisieren oder was auch immer sonst noch nötig wäre) und diese dann an die Mainform zu Darstellung weitergeben.


Talemantros - Sa 02.01.16 23:17

Hallo Ralf,
War ja wieder klar , dass es nicht so einfach ist. :-)
Kennst mich bestimmt schon gut genug um zu wissen, dass ich mich zum weiter entwickeln eher für den Message Broker interessiere.

Ich versuche da im Netz mal was zu finden.
Mache den Eintrag hier erst mal zu um keine Verwirrung zu stiften und dann zum Message Broker einen neuen auf, wenn ich es mal alleine versucht habe.

Gruß