2017-02-03 5 views
0

Ich versuche, einen Weg zu finden, um das übergeordnete Element eines Thread eines Winform zurück in den GUI-Thread zu ändern. Im Moment muss ich das Formular von einem anderen Thread erstellen, aber Zugriff wird unmöglich von der Hauptform, die den Verweis darauf hat.Ändern Sie den übergeordneten Thread eines Formulars

hier eine Probe von dem, was ich

public partial class MainForm : Form 
{ 
    // local instance of the sub form 
    private ViewForm SubForm { get; set;} = null; 

    public MainForm() 
    { 
     InitializeComponent(); 

     Task.Run(() => 
     { 
      // set the sub form    
      SubForm = new ViewForm(); 
     } 

     // call the rest of the initialization of main form 
     InitializeCustomControls(); 
    } 

    private void OpenViewWindow_Click(object sender, EventArgs e) 
    { 
     // if the window is instanciated 
     if (SubForm != null) 
     { 
      SubForm.Show();     
     } 
    }   
} 

Das ViewForm Fenster haben, ist kein Form Objekt. Es ist ein benutzerdefiniertes Fenster von Drittanbietern. Es hat viele Steuerelemente und Vorlagen mit Themen gemischt. Der einzige Aufruf eines neuen leeren Konstruktors kann bis zu 7 Sekunden dauern, weshalb ich ihn in einem anderen Thread erstellen muss, während ich weiterhin mein Hauptfenster lade.

Im Moment kann ich jede Methode im Fenster außer .Show() anrufen, die immer aufgrund von Thread Erstellungsbeschränkung fehlschlagen. Ich möchte mich davon abhalten, den Thread als endlos laufenden Thread zu erstellen, der warten und ein Objekt lesen wird, um ihm zu sagen, wann er das Fenster anzeigen und verstecken soll.

das ist der .Show() Fehler:

Cross-thread operation not valid: Control 'ViewForm' accessed from a thread other than the thread it was created on.

ich folgendes stattdessen versuchte aber es meine Schnittstelle noch gefrieren:

Task.Run(() => 
{ 
    // set the sub form 
    this.Invoke(new MethodInvoker(delegate 
    { 
     SubForm = new ViewForm(); 
    })); 
} 

Was ich so etwas wie ein Feuer möchten und vergessen Instantiierung eines GUI-Objekts.

+0

Ich habe nicht Ihre ganze Post gelesen, aber der Titel Ihrer Frage und der erste Satz fiel auf. Die Antwort ist: Sie sollten * NIE * UI-Code auf etwas anderem als dem Hauptthread ausführen, um damit zu beginnen. Es ist eine goldene Regel in der UI-Programmierung. Wenn Sie dem folgen, haben Sie dieses Problem nicht. –

+2

Wenn Sie ein Formular eines Drittanbieters haben, das den UI-Thread beim Start 7 Sekunden lang einfriert, hat es einen schwerwiegenden Fehler. Verwenden Sie dieses Buggy-Formular von Drittanbietern nicht, oder lassen Sie den Fehler beheben. – Servy

+0

@ rory.ap Während dies die gleiche erste Reaktion war, ist der Buggy-Code offensichtlich im 3rd-Party-Code, also ist es keine Regel, die das OP in der Lage ist zu erzwingen. – Servy

Antwort

0

Heres eine Lösung unter Verwendung eines BackGroundWorker:

public partial class MainForm : Form 
{ 
    // local instance of the sub form 
    private ViewForm SubForm { get; set;} = null; 

    public MainForm() 
    { 
     InitializeComponent(); 
     backGroundWorker1.RunWorkerAsync(); 
     InitializeCustomControls(); 
    } 

    private void OpenViewWindow_Click(object sender, EventArgs e) 
    { 
     // if the window is instanciated 
     if (SubForm != null) 
     { 
      SubForm.Show();     
     } 
    } 

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
    { 
     SubForm = new ViewForm(); 
    } 
} 

Getestet zwei Formen zu schaffen, die MainForm ziemlich ähnlich wie die, in der Probe und die SubView Form mit einem Threading.Sleep(10000) auf dem Konstruktor.

+0

das funktioniert perfekt und ich brauche das nicht m wie @Gusman Trick angezeigt. Dies wird sehr nützlich sein, da ich ein paar dieser Fenster zum Vorladen habe, um bei Bedarf fertig zu sein. – Franck

Verwandte Themen