2011-11-08 183 views
0

我最近發表了一篇關於此的文章,但我認爲我的最後一個問題沒有寫得很好,我確實得到了答案,但我想看看是否有更簡單的解決方案,因爲我發現最後一個問題令人困惑。這次我試圖儘可能清楚地寫出它。新線程打開新窗口,如何在新窗口中更新文本框?

我這裏WPF應用程序下面的代碼是代碼MainWindow.xaml.cs

public MainWindow() 
{ 
    InitializeComponent(); 
} 

private void button1_Click(object sender, RoutedEventArgs e) 
{ 
    Thread[] threads = new Thread[3]; 

    for (int i = 0; i < 3; i++) 
    { 
    int index = i; 
    threads[i] = new Thread(new ThreadStart(test)); 
    threads[i].SetApartmentState(ApartmentState.STA); 
    threads[i].IsBackground = true; 
    threads[i].Start(); 
    } 
} 

public void test() 
{ 
    OutputWindow outputwindow = new OutputWindow(); 
    outputwindow.Show(); 
    System.Windows.Threading.Dispatcher.Run(); 

    outputwindow.textBox1.Text = "writing"; 
    //some more stuff done 
    //some more stuff done 
    //some more stuff done 
    outputwindow.textBox1.Text = "\nmore writing"; 
    //some more stuff done 
    //some more stuff done 
    //some more stuff done 
    outputwindow.textBox1.Text = "\nmore writing"; 
} 

我怎樣才能讓textBox1.Text真正得到更新測試()是

代碼正在執行?

問候!

編輯

謝謝您的回答,但我無法使它工作還沒有。

這是一個網絡應用程序,所以我認爲文本框比數據綁定更合適,因爲我想在整個程序中打印超時,ping和更多信息,以確保一切按計劃進行。

我試了一些你的答案,但我無法讓它工作。這是我試過的最後一個例子,它不起作用

public MainWindow() 
{ 
    InitializeComponent(); 
} 

private void button1_Click(object sender, RoutedEventArgs e) 
{ 
    Thread[] threads = new Thread[3]; 

    for (int i = 0; i < 3; i++) 
    { 
    int index = i; 
    threads[i] = new Thread(new ThreadStart(test)); 
    threads[i].SetApartmentState(ApartmentState.STA); 
    threads[i].IsBackground = true; 
    threads[i].Start(); 
    } 
} 

public void test() 
{ 
    OutputWindow outputwindow = new OutputWindow(); 
    outputwindow.Show(); 
    System.Windows.Threading.Dispatcher.Run(); 

    outputwindow.textBox1.Text = "writing"; 
    //some more stuff done 
    //some more stuff done 
    //some more stuff done 
    outputwindow.textBox1.Text = "\nmore writing"; 
    //some more stuff done 
    //some more stuff done 
    //some more stuff done 
    Action action =() => outputwindow.textBox1.Text = "\nmore writing"; 
    Dispatcher.Invoke(action); 
} 

回答

1

我已經回答了您的最後一個問題,然後我看到了這一個。我已經得出結論,你想要另一個意見,所以你再次問,我不是故意回答這個問題,但我看到你沒有走多遠,所以我會再試一次。

代碼示例的問題在於您調用Dispatcher.Run()。問題是,你真的必須調用Dispatcher.Run來保持你的窗口文本框活着和響應,但在裏面的Dispatcher.Run方法是無限循環。你被困在分派器上。運行代碼行,直到Dispatcher關閉並且窗口關閉。只有這樣你的代碼才能繼續執行,並執行那些outputWindow.textBox1.Text集合語句,但現在已經太遲了。解決您的問題的方法是將outputWindow與「工作代碼」分開。

對代碼的最簡單修改是將您的「工作代碼」放在另一個線程中,這樣您就不會被Dispatcher.Run()阻塞。以下是示例代碼的外觀(因爲您更喜歡使用相同的方法創建outputWindow)。

// all good here 
    public MainWindow() 
    { 
     InitializeComponent(); 
    } 

    // also all good here 
    private void button1_Click(object sender, RoutedEventArgs e) 
    { 
     Thread[] threads = new Thread[3]; 

     for (int i = 0; i < 3; i++) 
     { 
      int index = i; 
      threads[i] = new Thread(new ThreadStart(test)); 
      threads[i].SetApartmentState(ApartmentState.STA); 
      threads[i].IsBackground = true; 
      threads[i].Start(); 
     } 
    } 

    // here's the change 
    public void test() 
    { 
     OutputWindow outputwindow = new OutputWindow(); 
     outputwindow.Show(); 

     // here you create another thread which will execute your work code (the one you had after the Dispatcher.run statement 
     Thread workThread = new Thread(new ParameterizedThreadStart(workMethod)); 
     workThread.IsBackground = true; 
     // start the work thread BUT transfer the reference to outputwindow 
     workThread.Start(outputwindow); 

     System.Windows.Threading.Dispatcher.Run(); 

     // no more code here; it has been transferd to workMethod which runs in another thread 
    } 

    public void workMethod(object threadParam) 
    { 
     OutputWindow outputwindow = (OutputWindow)threadParam; 

     // those are little ugly but you must go through dispatcher because you are now in a different thread than your outputwindow 
     outputwindow.Dispatcher.BeginInvoke((Action)(() => { outputwindow.textBox1.Text = "writing"; }), System.Windows.Threading.DispatcherPriority.Normal); 
     //some more stuff done 
     //some more stuff done 
     //some more stuff done 
     outputwindow.Dispatcher.BeginInvoke((Action)(() => { outputwindow.textBox1.Text = "\nmore writing"; }), System.Windows.Threading.DispatcherPriority.Normal); 
     //some more stuff done 
     //some more stuff done 
     //some more stuff done 
     outputwindow.Dispatcher.BeginInvoke((Action)(() => { outputwindow.textBox1.Text = "\nmore writing"; }), System.Windows.Threading.DispatcherPriority.Normal); 

     // and finally close the outputWindow 
     outputwindow.Dispatcher.InvokeShutdown(); 
    } 
+0

欣賞它。非常感謝。 – Arya

+0

有沒有辦法在窗戶關閉時使工作方法停止工作?現在我每秒用一次無限循環嘗試使用Console.beep(),即使關閉窗口,我仍然可以聽到蜂鳴聲。 – Arya

+0

我開始使用製表符,它運行得更好 – Arya

0

的問題是,該更新將要到當前的方法退出處理。您需要泵送消息泵,以便在當前方法退出之前應用消息泵。對於如何做到這一點的例子見here

public static void DoEvents(this Application application) 
{ 
    Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, new VoidHandler(() => { })); 
} 

private delegate void VoidHandler(); 

這麼說,我覺得你的設計是想,可能通過使用更標準的機制,如BackgroundWorker大大提高。

0

正如其他人在這裏寫的,你需要調用,如果你想改變UI對象。但你有沒有給它可能使用數據綁定而不是?這是一個很好的方式來使用WPF來實際綁定數據(在你的情況下是一個字符串)。

有一些教程在這裏:http://www.wpftutorial.net/DataBindingOverview.html

從長遠來看,你甚至想看看在MVVM模式,但它至少一開始就開始使用數據綁定。