Laden...

Panel nicht angezeigt

Erstellt von Luth vor 17 Jahren Letzter Beitrag vor 17 Jahren 1.912 Views
L
Luth Themenstarter:in
36 Beiträge seit 2006
vor 17 Jahren
Panel nicht angezeigt

Hallo zusammen,

ich möchte aus einem anderen Thread auf ein Form zugreifen.
Das funktioniert über BeginInvoke() auf einen Delegaten auch ganz gut, die Methode wird aufgerufen und Form.Text und ein Label nehmen die neuen Werte an.

Warum wird nun aber mein Panel bzw. der Button darauf nicht angezeigt? Ich nehme an ich habe etwas wesentliches übersehen und finde es nur nicht da ich mich seit einer ganzen Weile nicht mehr mit Forms beschäftigt habe.

Noch eine Frage hinterher:
Wenn ich einen neuen Thread starte und das Form mit ShowDialog() anzeige, wird der Thread beendet wenn das Form geschlossen wird?

Danke schonmal für eure Antworten.

Formerstellung, Updatemethode und Threadstart


protected override void startProcessing()
        {
            //Create the form that is showed on screen
            thread = new Thread(new ThreadStart(startFormThread));
            thread.Start();
        }

void outputMgr_ContainerChange(ContainerChangeEventArgs e)
        {
            form.BeginInvoke(form.delegateUpdateForm, e.NewContainer);
        }


private void startFormThread()
        {
            form = new TSForm();
            form.ShowDialog();
            
        }

protected override void shutDownDevice()
        {
            form.BeginInvoke(delegateCloseForm);
        }

Das Formelement:


class TSForm:Form
{
        private Label infoline;
        private Panel p;

        public delegate void DelegateUpdateForm(Container c);
        public DelegateUpdateForm delegateUpdateForm;
        
        public delegate void DelegateCloseForm();
        public DelegateCloseForm delegateCloseForm;


        public TSForm()
        {
            SystemSettings.ScreenOrientation = ScreenOrientation.Angle90;
            this.ControlBox = false;
            this.Width = 320;
            this.Height = 200;
            this.Text = "Testform";
            
            infoline = new Label();
            infoline.Text = "Info:";
            infoline.Width=200;
            infoline.Height=30;
            infoline.Anchor = AnchorStyles.Top;
            Controls.Add(infoline);

            delegateUpdateForm = new DelegateUpdateForm(updateContainer);
            delegateCloseForm = new DelegateCloseForm(closeForm);
        }

        private void updateContainer(Container c)
        {
            ListSelector ls = (ListSelector)c.Elements[0];
            this.Text = c.Name + "<->" + ls.Name + "<->" + ls.Options[ls.SelectedOption].Name;
            this.infoline.Text = ls.Options[ls.SelectedOption].Name;

            p = new Panel();
            p.Size = new Size(200, 200);
            p.Visible = true;
            p.Anchor = AnchorStyles.Bottom;

            Button b1 = new Button();
            b1.Text = ls.Options[ls.SelectedOption].Name;
            b1.Size = new Size(100, 20);

            p.Controls.Add(b1);

            Controls.Add(p);
            this.Refresh();
            this.Update();
            this.Show();
            UICore.Logger.Info("Anzahl Controls: " + this.Controls.Count);
        }
}

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo Luth,

Forms und Controls sollten ohnehin nicht in einem anderen Thread als dem GUI-Thread erzeugt werden. Insbesondere dürfen einzelne Controls einen Forms nicht von einem anderen Thread erstellt werden.

Ein Thread (der nicht von außen abgebrochen wird) wird genau dann beendet, wenn die ThreadStart-Methode verlassen wird. Also nicht dadurch, dass ein ShowDialog beendet ist, es sei denn, dass ist die letzte Anweisung in der ThreadStart-Methode. Aber ShowDialog sollte eben ohnehin nicht in einen extra Thread.

herbivore

L
Luth Themenstarter:in
36 Beiträge seit 2006
vor 17 Jahren

Hallo Herbivore und erstmal danke für die Antwort.

Meine Anwendung ist als Konsolenanwendung für einen PDA konzipiert die ein Benutzerinterface für Blinde oder Sehebhinderte anbieten soll. Die Beschreibung der Dialoge erfolgt in einer einfachen Sprache in einer XML-Datei, welche zum Beispiel das im Quellcode erwähnte Container-Element beschreibt.

Die Beschreibung wird dann von einem Renderer, z. Bsp. Text to Speech-Engine, Braillezeile oder graphisch auf einem Touchscreen dargestellt. Ähnlich divers sind die Eingabegeräte. Es bietet sich daher nicht an das ganze als WinForm-Anwendung hochzuziehen und vom Standard-GUI-Thread aus zu arbeiten. Daher die Auslagerung in einen extra Thread, der quasi als GUI Thread agieren soll.

Nun zurück zum eigentlichen Problem:

Die neuen Elemente werden ja in der updateContainer Methode erzeugt. Diese wurde durch ein BeginInvoke auf den entsprechenden Delegate aufgerufen. Das ganze sollte sich also im Thread-Context des Forms abspielen. Oder etwa nicht? Der Zugriff auf das Infolabel und Form.Text erfolgt in der gleichen Methode und dort funktioniert die Änderung der entsprechenden Werte. Ich bekomme keinerlei Ausnahmen das ich auf den GUI-Thread nicht von außen zugreifen darf, aber halt auch die neuen Elemente nicht angezeigt. Warum ist das so? Deine Erklärung habe ich nicht leider verstanden.

Und wenn es so nicht geht, gibt es einen Weg bei Invoke der updateContainer-Methode Controls zu entfernen oder hinzuzufügen?

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo Luth,

ich habe wiederum deine Erklärung mit der Konsolenanwendung nicht verstanden. 🙂 Du arbeitest doch nun mal mit Forms. Von daher hast du den Charakter eine Windows-Forms Anwendung und musst die Restriktionen beachten.

Wenn du Invoke benutzt, landest du in dem Thread, der das Form/Control erzeugt hat, auf das du Invoke anwendest. Wenn die anderen Zugriffe gehen, würde ich vermuten, dass du im richtigen Thread bist.

Bei den Controls, die du erzeugst, setzt du Location nicht. Vielleicht sind sie einfach nur außerhalb des sichtbaren Bereichs platziert.

herbivore

L
Luth Themenstarter:in
36 Beiträge seit 2006
vor 17 Jahren

Hallo nochmal,

ich habe mal nach den Locations geschaut. Du hattest natürlich recht mit deinem Tip. Wenn ich die alle "von Hand" setze, geht es. Wahrscheinlich hätte ich noch ewig danach gesucht. Ich bin davon ausgegangen, dass ein Control welches als letztes zu Form.Controls hinzugefügt wird, die anderen überzeichnet, so das wenigstens irgendwas zu sehen sein müsste. Scheinbar wird es aber in einigen Fällen einfach nicht gezeichnet, wenn sich die Location mit anderen mit Controls überschneidet. Danke nochmal für den Tip.


Und meine letzte Erklärung war vielleicht etwas undeutlich. Ich weis vor Programmstart nicht, was für Ein- und Ausgabegeräte angesprochen werden. Das ist in einer Config-Datei festgelegt die bestimmt wie meine Dialogbeschreibung interpretiert werden soll. Eine visuelle Ausgabe mit Forms kann dabei sein, ist es in vielen Fällen aber nicht. Für Tastatureingaben oder Mauseingaben greife ich daher ebenfalls nicht auf die Form-Events zurück, sondern nutze einen globalen Hook der mir alle WindowsMessages abfängt.

Daher bringt es mir wenig die Anwendung als WindowsForms-Anwendung zu programmieren, wenn die Forms recht häufig weder für Eingabe- noch für Darstellung verwendet werden. Deswegen habe ich mich für eine Konsolenanwendung mit optionaler Ausgabe über WindowsForms als Ausgangspunkt entschieden. Mit den daraus enstehenden Zugriffs-Beschränkungen habe ich beschlossen zu leben. 😉

Edit 2:

Kann ich hier irgendwo ein Häkchen setzen um den Thread als beantwortet/erledigt zu deklarieren? Ich finde da gerade nix. ^^

N
750 Beiträge seit 2004
vor 17 Jahren

Original von Luth
Kann ich hier irgendwo ein Häkchen setzen um den Thread als beantwortet/erledigt zu deklarieren? Ich finde da gerade nix. ^^

Hallo Luth,

häkchen setzen geht leider nicht, aber du könntest deinen ersten beitrag editieren und bei "Thema" ein "[erledigt]" oder "[gelöst]" voranstellen.
Wenn du ein bisschen im Forum guckst, findest du sowas auch von anderen Usern. 🙂

nils

?( wer suchet, der findet auch! :]