backgroundworker 中的 C# ProgressBar 数据绑定

C# ProgressBar Databindings in 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();
    }
}

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

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

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

您的代码无法正常工作,因为您尝试从非 ui 线程更新 UI。您需要将代码包装在 Invoke() 调用中,例如在表单上使用代理 属性:

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