我尝试创建一个wpf应用程序,在文本框上显示正在运行的进程状态。此运行进程将在工作线程上运行,每次进程状态更改时,它也应更改文本框文本。
负责改变状态的类看起来
public class OutputText
{
public event ProcessEventArgsHandler processEventArgsHandler;
private void OnProcessHandler(String text)
{
if (processEventArgsHandler != null)
{
processEventArgsHandler(this, new ProcessEventArgs(text));
}
}
public void SimulateProcessOutput()
{
OnProcessHandler("Process Started.");
Thread.Sleep(200);
OnProcessHandler("Process 1");
Thread.Sleep(200);
OnProcessHandler("Process 2");
Thread.Sleep(200);
OnProcessHandler("Process 3");
Thread.Sleep(200);
OnProcessHandler("Process 4");
Thread.Sleep(200);
OnProcessHandler("Process Ended.");
}
}
查看SimulateProcessOutput()方法,稍后将调用事件处理程序来更改文本。
事件
public class ProcessEventArgs : EventArgs
{
private readonly String _state;
public String State
{
get { return _state; }
}
public ProcessEventArgs(String state)
{
_state = state;
}
}
和委托
public delegate void ProcessEventArgsHandler(object s, ProcessEventArgs e);
最后,wpf代码
public partial class MainWindow : Window
{
private static Task _task;
private static TaskScheduler _taskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
private static CancellationToken _cancelToken = new CancellationToken();
public static Task ProTask {
get { return _task; }
}
public MainWindow()
{
InitializeComponent();
}
private void ProcessEventHandler(object s, ProcessEventArgs e)
{
_processText.Text = e.State;
}
private void StartProcess()
{
var outputText = new OutputText();
outputText.processEventArgsHandler += ProcessEventHandler;
outputText.SimulateProcessOutput();
}
private void MainWindow_OnLoaded(object sender, RoutedEventArgs e)
{
Task.Factory.StartNew(StartProcess, _cancelToken, TaskCreationOptions.None, _taskScheduler);
}
}
当我运行应用程序时,只显示最后一个文本,另一个文本没有出现。
流程结束
我如何编程应用程序,文本框一个接一个地显示文本,如
流程已开始。
等待200毫秒
流程1.
........
答案 0 :(得分:2)
我认为你不需要显示所有这些代码,问题就在于此处
_processText.Text = e.State;
将其替换为
_processText.AppendText(e.State);
_processText.AppendText(Environment.NewLine);
因为很明显,= e.State
将替换内容,实际上只显示最后传递的文本。
修改
好的,那不是问题。问题是这里的Task实际上是UI线程阻塞。您可能希望使用Task.ContinueWith重写代码。您可以在网上轻松找到examples。
或者,如果你使用的是C#4.5 / 5,你也可以做一些neat thing with async/await。
答案 1 :(得分:1)
我找到了解决方案Dispatcher.Invoke,这里是代码:
public partial class MainWindow : Window
{
private static Task _task;
private static TaskScheduler _taskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
private static CancellationToken _cancelToken = new CancellationToken();
public static Task ProTask {
get { return _task; }
}
public MainWindow()
{
InitializeComponent();
}
private void ProcessEventHandler(object s, ProcessEventArgs e)
{
Dispatcher.Invoke(DispatcherPriority.Normal,
(Action)(() => { _processText.Text = e.State; }));
}
private void StartProcess()
{
var outputText = new OutputText();
outputText.processEventArgsHandler += ProcessEventHandler;
outputText.SimulateProcessOutput();
}
private void MainWindow_OnLoaded(object sender, RoutedEventArgs e)
{
Task.Factory.StartNew(StartProcess);
}
}
使用Dispatcher添加ProcessEventHandler,可以控制UI线程。阅读文章Dispatcher