在启动线程之前无法更改WPF控件状态

时间:2014-01-09 12:10:27

标签: c# wpf multithreading

我想在点击按钮开始后更改wpf控件状态。

图片就是我想要的。

what I want

以下是我的代码

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()添加到我的代码

3 个答案:

答案 0 :(得分:3)

  

//等待线程退出

后台线程的重点是通过阻止UI线程等待它。不。

相反,让线程在完成后通知你的用户界面。

答案 1 :(得分:0)

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

答案 2 :(得分:0)

可行的代码

    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);
    }