如何在新线程打开的新窗口中更新文本框?

时间:2011-11-06 07:33:20

标签: c# wpf multithreading

我可以通过以下代码在新线程中打开一个新窗口。

以下代码来自MainWindow.xaml.cs

private void buttonStartStop_Click(object sender, RoutedEventArgs e)
{    

  Test test = new Test();

  Thread newWindowThread = new Thread(new ThreadStart(test.start));
  newWindowThread.SetApartmentState(ApartmentState.STA);
  newWindowThread.IsBackground = true;
  newWindowThread.Start();
}

以及test.start()

中的以下内容
public void start()
{

  OutputWindow outputwindow = new OutputWindow();
  outputwindow.Show();


  Output.print("Begin");
  System.Windows.Threading.Dispatcher.Run();
  Output.print("FINAL");
  System.Windows.Threading.Dispatcher.Run();

}

以下内容来自输出类

public static void print(String str)
{
  Dispatcher uiDispatcher = OutputWindow.myOutputWindow.Dispatcher;
  uiDispatcher.BeginInvoke(new Action(delegate() { OutputWindow.myOutputWindow.textBoxOutput.AppendText(str + "\n"); }));
  uiDispatcher.BeginInvoke(new Action(delegate() { OutputWindow.myOutputWindow.textBoxOutput.ScrollToLine(OutputWindow.myOutputWindow.textBoxOutput.LineCount - 1); }));
}

public static void printOnSameLine(String str)
{
  Dispatcher uiDispatcher = OutputWindow.myOutputWindow.Dispatcher;
  uiDispatcher.BeginInvoke(new Action(delegate() { OutputWindow.myOutputWindow.textBoxOutput.AppendText(str); }));
  uiDispatcher.BeginInvoke(new Action(delegate() { OutputWindow.myOutputWindow.textBoxOutput.ScrollToLine(OutputWindow.myOutputWindow.textBoxOutput.LineCount - 1); }));
}

“Begin”是否在文本框中打印但“FINAL”没有打印,我希望Test类中的start方法通过程序更新outputwindow中的文本框。这样做的最佳方式是什么?

提前谢谢

2 个答案:

答案 0 :(得分:0)

我不确定你想做什么。由于您调用了System.Windows.Threading.Dispatcher.Run(),因此无法打印FINAL是正常的。此方法使线程保持活动状态并侦听事件。你可以看一下它,就像你在Run方法中有while(true){}一样。方法将继续运行,直到Dispatcher关闭。您应该保持后台线程处于活动状态,并在需要设置消息时从另一个线程调用静态方法。这是一个例子:

        // reference to window in another thread
        Window outputWindow = null;

        Thread thread = new Thread(() =>
        {
            // another thread
            outputWindow = new Window();
            outputWindow.Show();
            // run event loop
            System.Windows.Threading.Dispatcher.Run();
        }) { ApartmentState = ApartmentState.STA, IsBackground = true };
        thread.Start();

        while (outputWindow == null)
        {
            // wait until the window in another thread has been created
            Thread.Sleep(100);
        }

        // simulate process
        for (int i = 0; i < 10; i++)
        {
            outputWindow.Dispatcher.BeginInvoke((Action)(() => { outputWindow.Title = i.ToString(); }), System.Windows.Threading.DispatcherPriority.Normal);
            Thread.Sleep(500); // simulate some hard work so we can see the change on another window's title
        }

        // close the window or shutdown dispatcher or abort the thread...
        thread.Abort();

修改

这可能很快&amp;脏的通用解决方案DoSomeHardWork为等待窗口创建另一个GUI线程,显示进度信息。这个窗口创建了实际完成工作的工作线程。工作在方法Action中实现。第一个参数是等待窗口,因此您可以从工作线程更改它。当然,在现实世界中,你应该通过接口而不是直接进行窗口实现,但这只是一个例子。第二个参数是对象,因此您可以将所需的任何内容传递给工作线程。如果需要更多参数传递object []或修改方法签名。在这个例子中,我用计数器和睡眠来模拟努力工作。您可以多次单击按钮执行此代码,您将看到所有等待窗口计数自己的计数器而不冻结。这是代码:

    public static void DoSomeHardWork(Action<Window, object> toDo, object actionParams)
    {
        Thread windowThread = new Thread(() =>
        {
            Window waitWindow = new Window();
            waitWindow.Loaded += (s, e) =>
            {
                Thread workThread = new Thread(() =>
                {
                    // Run work method in work thread passing the
                    // wait window as parameter
                    toDo(waitWindow, actionParams);
                }) { IsBackground = true };
                // Start the work thread.
                workThread.Start();
            };
            waitWindow.Show();
            Dispatcher.Run();
        }) { ApartmentState = ApartmentState.STA, IsBackground = true };
        // Start the wait window thread.
        // When window loads, it will create work thread and start it.
        windowThread.Start();
    }

    private void MyWork(Window waitWindow, object parameters)
    {
        for (int i = 0; i < 10; i++)
        {
            // Report progress to user through wait window.
            waitWindow.Dispatcher.BeginInvoke((Action)(() => waitWindow.Title = string.Format("{0}: {1}", parameters, i)), DispatcherPriority.Normal);
            // Simulate long work.
            Thread.Sleep(500);
        }
        // The work is done. Shutdown the wait window dispather.
        // This will stop listening for events and will eventualy terminate
        // the wait window thread.
        waitWindow.Dispatcher.InvokeShutdown();
    }

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        DoSomeHardWork(MyWork, DateTime.Now);
    }

答案 1 :(得分:0)

理想情况下,创建UI元素的线程(UI线程)也拥有元素。使用调度程序,您所做的就是将非UI相关处理推送到后台线程。后台进程完成后,结果将再次推送回主UI线程。有关示例示例,请查看:http://weblogs.asp.net/pawanmishra/archive/2010/06/06/understanding-dispatcher-in-wpf.aspx