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);
}
我不是 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);
}