我不是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();
}
}
答案 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?