2011-11-08 147 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模式,但它至少一开始就开始使用数据绑定。