【问题标题】:Cannot change WPF controls status before starting thread在启动线程之前无法更改 WPF 控件状态
【发布时间】:2014-01-27 23:36:26
【问题描述】:

我想在点击按钮启动后更改 wpf 控件的状态。

图片就是我想要的。

以下是我的代码

private bool _bWorking = false;
public delegate void UpdateStatusDelegate();

private void SetStatus(bool bEnable)
{
    if (bEnable)
    {
        tbName.IsReadOnly = false;
        barStatus.Visibility = Visibility.Hidden;
        btnStart.IsEnabled = true;
        btnStop.IsEnabled = false;
        btnClose.IsEnabled = true;
    }
    else
    {
        tbName.IsReadOnly = true;
        barStatus.Visibility = Visibility.Visible;
        btnStart.IsEnabled = false;
        btnStop.IsEnabled = true;
        btnClose.IsEnabled = false;
    }
}

internal void UpdateStatus()
{
   SetStatus(true);
   _bWorking = false;
}

private void ThreadFunc()
{
    //for (; ; )
    //{
    //    // do something here
    //    if (_bWorking == false)
    //        break;
    //}
    Thread.Sleep(500);
    this.Dispatcher.Invoke(new UpdateStatusDelegate(UpdateStatus));
}

private void btnStart_Click(object sender, RoutedEventArgs e)
{
    _bWorking = true;
    SetStatus(false);
    this.UpdateLayout();//this.InvalidateVisual();
    try
    {
        Thread t = new Thread(new ThreadStart(() =>
        {
            ThreadFunc();
        }));
        t.IsBackground = true;
        t.Name = "test status";
        t.Start();

        while (t.IsAlive)
        {
            // wait thread exit
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }        
}

private void btnStop_Click(object sender, RoutedEventArgs e)
{
    _bWorking = false;
    SetStatus(true);
}

但实际上在我点击开始按钮后,UI似乎冻结了,线程退出后,UI恢复正常。

我的VS是VS2010。

Force a WPF control to refresh?

这篇文章不适合我。

编辑摘要:

将委托 void UpdateStatusDelegate() 和函数 UpdateStatus() 添加到我的代码中

【问题讨论】:

标签: c# wpf multithreading


【解决方案1】:

//等待线程退出

后台线程的全部意义在于通过阻塞你的 UI 线程来等待它。不要。

相反,让线程在完成后通知您的 UI。

【讨论】:

  • 但是您想在线程完成后更改您的 UI。如果您 wait 等待线程,则不需要线程,您可以在没有第二个线程的情况下执行此操作。你不想等待,你希望你的线程在它可以做你想做的事情时通知你的用户界面。
  • 我添加了委托 void UpdateStatusDelegate() 和函数 UpdateStatus()。还是不行。
  • @Rock 你的等待循环仍然很忙。放弃等待线程。
  • 我仍然无法点击停止按钮。
  • 我使用秒表来模拟作业。现在可以了。谢谢。
【解决方案2】:

尝试使用 BackgroundWorker 组件可能会对您有所帮助。欲了解更多信息,请查看MSDN article

【讨论】:

    【解决方案3】:

    可行的代码

        public delegate void UpdateStatusDelegate();
        private bool _bWorking = false;
    
        private void SetStatus(bool bEnable)
        {
            if (bEnable)
            {
                tbName.IsReadOnly = false;
                barStatus.Visibility = Visibility.Hidden;
                btnStart.IsEnabled = true;
                btnStop.IsEnabled = false;
                btnClose.IsEnabled = true;
            }
            else
            {
                tbName.IsReadOnly = true;
                barStatus.Visibility = Visibility.Visible;
                btnStart.IsEnabled = false;
                btnStop.IsEnabled = true;
                btnClose.IsEnabled = false;
            }
        }
    
        internal void UpdateStatus()
        {
            SetStatus(true);
        }
    
        private void ThreadFunc()
        {
            try
            {
                // use Stopwatch to simulate jobs
                var watch = Stopwatch.StartNew();
                for (; ; )
                {
                    var elapsedMs = watch.ElapsedMilliseconds;
                    if (elapsedMs > 10000 // 10 seconds
                        || _bWorking == false)
                    {
                        break;
                    }
                }
                watch.Stop();
                this.Dispatcher.Invoke(new UpdateStatusDelegate(UpdateStatus));
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            _bWorking = false;
        }
    
        private void btnStart_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                _bWorking = true;
                SetStatus(false);
                Thread t = new Thread(new ThreadStart(() =>
                {
                    ThreadFunc();
                }));
                t.IsBackground = true;
                t.Name = "test status";
                t.Start();
                //while (t.IsAlive)
                {
                    // wait thread exit
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
    
        private void btnStop_Click(object sender, RoutedEventArgs e)
        {
            _bWorking = false;
            SetStatus(true);
        }
    

    【讨论】:

      猜你喜欢
      • 2021-10-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多