在WPF上执行工作线程并显示状态

时间:2014-05-28 10:22:13

标签: c# wpf multithreading

我尝试创建一个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.

     

........

2 个答案:

答案 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