我最近发了一篇关于此事的帖子,但我认为我的最后一个问题写得不好而且我确实得到了答案,但我想知道是否有一个更简单的解决方案,因为我发现最后一个令人困惑。这次我试着尽可能清楚地写出来。
我有一个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";
}
如何在执行test()时使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);
}
答案 0 :(得分:1)
我已经回答了你的上一个问题然后我看到了这个问题。我已经得出结论你想要另一个意见,所以你再问一次,我不是故意回答这个问题,但我发现你没有走得太远,所以我会再试一次。
您的代码示例的问题是您调用Dispatcher.Run()。问题是你真的必须调用Dispatcher.Run来保持你的窗口文本框保持活动和响应,但在Dispatcher.Run方法内部是无限循环。你被困在Dispatcher.Run代码行上,直到Dispatcher被关闭并且窗口关闭。只有这样,你的代码才会继续并执行那些outputWindow.textBox1.Text set语句,但现在为时已晚。解决问题的方法是将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();
}
答案 1 :(得分:0)
必须使用调度与调度程序来更新控件。 您可以参考以下链接。
http://www.switchonthecode.com/tutorials/working-with-the-wpf-dispatcher http://www.albahari.com/threading/part2.aspx#_Rich_Client_Applications
答案 2 :(得分:0)
问题是在当前方法退出之前不会处理更新。您需要抽取消息泵,以便在当前方法退出之前应用它们。有关如何执行此操作的示例,请参阅here:
public static void DoEvents(this Application application)
{
Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, new VoidHandler(() => { }));
}
private delegate void VoidHandler();
那就是说,我认为你的设计很缺乏,并且可以通过使用更加标准的机制来大大改善,例如BackgroundWorker
。
答案 3 :(得分:0)
正如其他人在这里写的那样,如果要更改UI对象,则需要调用。但是你有没有想过可能会使用数据绑定?这是一种使用WPF实际绑定数据的好方法(在您的情况下是一个字符串)。
这里有一些教程:http://www.wpftutorial.net/DataBindingOverview.html
从长远来看,你甚至想看看MVVM模式,但它至少是开始使用数据绑定的开始。