C#ProgressBar数据绑定在backgroundworker中

时间:2016-11-05 18:37:41

标签: c# multithreading winforms backgroundworker

我不是c#的专家,但我要做的是更新后台工作程序中的进度条。我正在使用以下代码:

progressBar1.DataBindings.Add("Value", _dm, "Progress", true,
                               DataSourceUpdateMode.OnPropertyChanged);

这在GUI线程上没有后台工作程序时执行。 Progress属性是一个属性,它从另一个后台工作者(我无权访问)的进度中更新(使用INotifyPropertyChanged)。

如何使其工作以便使用backgroundworker进行更新,而不是将其全部放在GUI线程上?

我的代码(简化):

class DownloadManager : INotifyPropertyChanged {
    public event PropertyChangedEventHandler PropertyChanged;

    private double _progressValue;

    public double Progress
    {
        get { return _progressValue; }
        private set
        {
            if (!value.Equals(_progressValue))
            {
                _progressValue = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Progress"));
            }
        }
    }

    public void Download()
    {
        var downloader = new Downloader();

        downloader.DownloadProgressChanged += (sender, e) 
              => Progress = e.ProgressPercentage;

        downloader.Execute();
    }
}

public partial class MainForm 
{
    private readonly DownloadManager _dm;
    public MainForm() 
    {
        InitializeComponent();
        _dm = new DownloadManager();
    }

    private void btnDownload_Click(object sender, EventArgs e)
    {
           //TRIED HERE ...
           progressBar1.DataBindings.Add("Value", _dm, "Progress", true,
                                          DataSourceUpdateMode.OnPropertyChanged);
            bwDownload.RunWorkerAsync();
        }
    }

    private void bwDownload_DoWork(object sender, DoWorkEventArgs e)
    {
        //AND TRIED HERE 
        progressBar1.DataBindings.Add("Value", _dm, "Progress", true, DataSourceUpdateMode.OnPropertyChanged);

        //THIS AINT WORKING EITHER
        if (progressBar1.InvokeRequired) {
            progressBar1.Invoke(new MethodInvoker(() 
                => progressBar1.DataBindings.Add("Value", _dm, "Progress", true,
                                      DataSourceUpdateMode.OnPropertyChanged)));
    }

        _dm.Download();
    }
}

2 个答案:

答案 0 :(得分:2)

应该在构造函数中创建数据绑定,因为您只需要创建绑定一次,而不是每次都需要创建绑定:

public MainForm() 
{
    InitializeComponent();
    _dm = new DownloadManager();
    progressBar1.DataBindings.Add("Value", _dm, "Progress", true, DataSourceUpdateMode.OnPropertyChanged);
}

您的代码无效,因为您尝试从非ui线程更新UI。您需要在Invoke()调用中包装代码,例如使用Form:

上的代理属性
public partial class MainForm
{   
    private double _progress;
    public double Progress
    {
        get { return _progress; }
        set
        {
            _progress = value;

            // If not in the UI thread -> wrap the update in an Invoke() call:
            if (this.InvokeRequired)
            {
                this.Invoke(new Action(() => progressBar1.Value = (int) _progress), new object[] { });
                return;
            }

            // Else update directly
            progressBar1.Value = (int) value;
        }
    }

    private readonly DownloadManager _dm;
    public MainForm()
    {
        InitializeComponent();
        _dm = new DownloadManager();

        // Bind _db.Progress <-> this.Progress
        DataBindings.Add("Progress", _dm, "Progress", true, DataSourceUpdateMode.OnPropertyChanged);
    }

答案 1 :(得分:0)

需要在UI线程中更新GUI元素。您需要使用Control.Invoke更新控件属性。莫拉关于这个问题:Data Binding on multi thread application?