【问题标题】:Updating Winforms UI in real time while waiting for a Parallel.ForEach在等待 Parallel.ForEach 时实时更新 Winforms UI
【发布时间】:2012-05-10 14:35:51
【问题描述】:

以下代码不能“实时”运行。目的是,当单击按钮时,验证后台线程上的一组数据。在验证所有数据之前,我不能允许真正的“提交”,但我确实希望文本框能够实时更新。

相反,文本框会一次更新为奇数。

我想正在发生的事情是 task.Wait 阻塞了 observable,因为我在主线程上观察,但我无法解决这个问题,因为我需要在主线程上更新。

(显然这只是一个概念证明)

一些相关的注释 - 这段代码是否保证线程安全?谢谢。

private Subject<int> _subject; 
    public Form1()
    {
        InitializeComponent();
    }

    private int sleep = 2000;
    private int i = 0;
    private void LongRunningValidation(int num)
    {
        if (num % 2 == 0) return;

        Thread.Sleep(sleep * (i++));

        _subject.OnNext(num);
    }


    private ConcurrentBag<int> _bag;
    private void simpleButton1_Click(object sender, EventArgs e)
    {
        _subject = new Subject<int>();
        _subject.SubscribeOn(Scheduler.TaskPool).ObserveOn(SynchronizationContext.Current).Synchronize().Subscribe(UpdateTextBox);

        _bag = new ConcurrentBag<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

        if(Validate())
        {
            //submit
        }
    }

    private bool Validate()
    {
        var task = Task.Factory.StartNew(StartValidationAsync);

        task.Wait();

        return true;
    }

    private void StartValidationAsync()
    {
        Parallel.ForEach(_bag, LongRunningValidation);
    }

    private void UpdateTextBox(int i)
    {
        textEdit1.Text = textEdit1.Text + "," + i;

    }
}

【问题讨论】:

    标签: c# c#-4.0 asynchronous system.reactive


    【解决方案1】:

    您的 Validate 方法不是异步的,正如您所说的阻塞主线程。尝试使用事件:

    public delegate void ValidatedHandler(bool validate);
    public event ValidatedHandler Validated;
    
    private void Validate()
        {
            var task = Task.Factory.StartNew(StartValidationAsync);
    
            if (Validated != null)
               Validated(true);
        }
    

    并订阅事件:

    private void simpleButton1_Click(object sender, EventArgs e)
    {
        _subject = new Subject<int>();
         _subject.SubscribeOn(Scheduler.TaskPool).ObserveOn(SynchronizationContext.Current).Synchronize().Subscribe(UpdateTextBox);
    
    _bag = new ConcurrentBag<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    
    this.Validated += OnValidated;
    }
    
    
    public void OnValidated(bool validate)
    {
            if(validate)
            {
                //submit
            }
    }
    

    【讨论】:

    • 我实际上刚刚意识到我应该只使用 Task.ContinueWith 然后“提交”,但我猜这是同样的想法。非常感谢您的帮助。
    【解决方案2】:

    Windows 窗体不会自动更新 UI,即使您正在运行后台线程。尝试对要更新的任何内容调用 Update()。

    【讨论】:

    • 谢谢,但这不是问题。根本问题是在任务(即后台线程上的并行 foreach)完成之前不会调用 UpdateTextBox 方法,因为 Wait 会阻塞 UI 线程。
    猜你喜欢
    • 2012-03-20
    • 1970-01-01
    • 1970-01-01
    • 2015-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多