2010-05-04 17 views
10

Ich habe eine Methode, die Hintergrund-Thread erstellen, um etwas zu tun. In diesem Hintergrund Thread erstelle ich ein Objekt. Aber dieses Objekt beim Erstellen zur Laufzeit gibt mir eine Ausnahme:Wie kann ich WPF-Steuerelemente in einem Hintergrundthread erstellen?

Der aufrufende Thread muss STA sein, weil viele UI-Komponenten dies erfordern.

Ich weiß, dass ich Dispatcher verwenden muss, um etwas an UI zu reflektieren. Aber in diesem Fall erstelle ich nur ein Objekt und nicht iterieren mit UI. Das ist mein Code:

public void SomeMethod() 
     { 
     BackgroundWorker worker = new BackgroundWorker(); 
     worker.DoWork += new DoWorkEventHandler(Background_Method); 
     worker.RunWorkerAsync(); 
     } 

    void Background_Method(object sender, DoWorkEventArgs e) 
     { 
     TreeView tv = new TreeView(); 
     } 

Wie kann ich Objekte im Hintergrund Thread erstellen?

ich WPF-Anwendung

+0

Noch eine Frage: ist es möglich, Hintergrund Worker-Methode einen Wert von bestimmten Typ zurückgeben? – Polaris

+2

Überprüfen Sie die e.Result-Eigenschaft in der RunWorkerCompleted-Methode. http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx. – Amsakanna

Antwort

6

TreeView ist ein UI-Steuerelement. Sie können UI-Steuerelemente nur in einem Benutzeroberflächenthread erstellen und bearbeiten. Sie können also nicht versuchen, dies zu tun.

Was Sie tun möchten, ist, all die zeitaufwendigen Arbeiten an dem Hintergrundthread auszuführen und dann zum UI-Thread "zurückzurufen", um die Benutzeroberfläche zu bearbeiten. Das ist eigentlich ganz einfach:

void Background_Method(object sender, DoWorkEventArgs e) 
{ 
    // ... time consuming stuff... 

    // call back to the window to do the UI-manipulation 
    this.BeginInvoke(new MethodInvoker(delegate { 
     TreeView tv = new TreeView(); 
     // etc, manipulate 
    })); 
} 

ich falsch die Syntax gewordene für BeginInvoke (es ist aus der Spitze von meinem Kopf), aber es irgendwie, den Sie gehen ...

+0

Ich bekomme einige Daten von Web-Service und Laufzeit verbringen eine Menge Zeit dafür. Deshalb möchte ich Daten im Hintergrund erhalten und mein treeView erzeugen, wenn Daten bereit sind. – Polaris

+0

Ich habe meine Antwort mit einigen weiteren Kommentaren aktualisiert, wie Sie im Benutzeroberflächenthread von einem Arbeitsthread aus Dinge tun können. –

0

Um Ihren Code einfach funktioniert , müssen Sie eine STA COM Wohnung durch den Aufruf Thread.SetApartmentState(ApartmentState.STA) beitreten. Da BackgroundWorker wahrscheinlich einen freigegebenen Threadpool verwendet, kann das Verbinden eines bestimmten Apartments andere Benutzer dieses Threadpools beeinträchtigen oder sogar fehlschlagen, wenn es bereits auf z. MTA vorher. Selbst wenn alles klappt, wäre Ihre neu erstellte TreeView mit diesem Arbeitsthread gesperrt. Sie könnten es nicht in Ihrem Haupt-UI-Thread verwenden.

Wenn Sie etwas genauer über Ihre wahren Absichten erklärten, würden Sie sicherlich bessere Hilfe bekommen.

0

Versuchen folgenden Code:

public void SomeMethod() 
{ 

System.ComponentModel.BackgroundWorker myWorker = new System.ComponentModel.BackgroundWorker(); 

myWorker.DoWork += myWorker_DoWork; 

myWorker.RunWorkerAsync(); 

} 

private void myWorker_DoWork(object sender, 
    System.ComponentModel.DoWorkEventArgs e) 
{ 
    // Do time-consuming work here 
} 
3

HTH:

void Background_Method(object sender, DoWorkEventArgs e) 
    { 
     // Time Consuming operations without using UI elements 
     // Result of timeconsuming operations 
     var result = new object(); 
     App.Current.Dispatcher.Invoke(new Action<object>((res) => 
      { 
       // Working with UI 
       TreeView tv = new TreeView(); 
      }), result); 
    } 
0
void Background_Method(object sender, DoWorkEventArgs e) 
{ 
    TreeView tv = new TreeView(); 
    // Generate your TreeView here 
    UIDispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => 
    { 
     someContainer.Children.Add(tv); 
    }; 
} 
0

löste ich mein Problem. Ich habe gerade e.Result Eigenschaft der RunWorkerCompleted-Methode verwendet. Ich bekomme Daten im Hintergrund Thread und dann diese Daten verwenden, wenn der Thread abgeschlossen ist. Danke jedem Körper für nützliche Methoden. Besonderer Dank an Veer, um eine Empfehlung über e.Result Eigentum zu geben.

+0

Wenn Sie die Benutzeroberfläche in bestimmten Intervallen aktualisieren möchten, können Sie den Parameter UserState der ReportProgress-Methode verwenden, um Ihre Daten zu senden und sie in Ihrer ProgressChanged-Methode zu verwenden, indem Sie e.UserState in den erforderlichen Typ umwandeln. – Amsakanna

0

Niemand diskutiert den Fall eines separaten STA-Threads im Detail (obwohl das Konzept genau das gleiche ist).

Lassen Sie sich also hinzugefügt eine einfache Registersteuer vorstellen, auf einer Schaltfläche klicken

private void button_Click(object sender, RoutedEventArgs e) 
    { 
     TabItem newTab = new TabItem() { Header = "New Tab" }; 
     tabMain.Items.Add(newTab); 
    } 

Wenn wir es an einem anderen STA-Thread bewegen

private void button_Click(object sender, RoutedEventArgs e) 
    { 
     Thread newThread = new Thread(new ThreadStart(ThreadStartingPoint)); 
     newThread.SetApartmentState(ApartmentState.STA); 
     newThread.IsBackground = true; 
     newThread.Start(); 
    } 
    private void ThreadStartingPoint() 
    { 
     TabItem newTab = new TabItem() { Header = "New Tab" }; 
     tabMain.Items.Add(newTab); 
    } 

wir natürlich ein System.InvalidOperationException

Jetzt bekommen, Was passiert, wenn wir die Kontrolle

private void AddToParent(string header) 
    { 
     TabItem newTab = new TabItem() { Header = header }; 
     tabMain.Items.Add(newTab); 
    } 
hinzufügen

Verwenden einer Delegate-Methode?

public void DelegateMethod(string header) 
    { 
     tabMain.Dispatcher.BeginInvoke(
       new Action(() => { 
        this.AddToParent(header); 
       }), null); 
    } 

es funktioniert, wenn man es so nennen

private void button_Click(object sender, RoutedEventArgs e) 
    { 
     Thread newThread = new Thread(new ThreadStart(ThreadStartingPoint)); 
     newThread.SetApartmentState(ApartmentState.STA); 
     newThread.IsBackground = true; 
     newThread.Start(); 
    } 
    private void ThreadStartingPoint() 
    { 
     DelegateMethod("new tab"); 
    } 

weil natürlich jetzt wir die visuelle Struktur in dem gleichen ursprünglichen Thread halten.

Verwandte Themen