如何将ProgressBar绑定到另一个线程中更新的类的属性?
以下代码示例显示了我的第一次天真尝试。它不起作用,因为我得到有关跨线程通信的运行时错误。我想我需要以某种方式使用Invoke,但我不确定如何使用Binding类。
using System;
using System.Drawing;
using System.Windows.Forms;
using System.ComponentModel;
using System.Threading;
class ProgressForm : Form
{
private ProgressBar pbProgress;
public ProgressForm(ref LongOp lo)
{
Binding b = new Binding("Value", lo, "Progress");
pbProgress = new ProgressBar();
pbProgress.DataBindings.Add(b);
this.Controls.Add(pbProgress);
}
}
class Program : Form
{
private Button btnStart;
private LongOp lo;
public Program()
{
lo = new LongOp();
btnStart = new Button();
btnStart.Text = "Start long operation";
btnStart.Click += new EventHandler(btnStart_Click);
this.Controls.Add(btnStart);
}
private void btnStart_Click(object sender, EventArgs e)
{
ProgressForm pf = new ProgressForm(ref lo);
lo.DoLongOp();
pf.ShowDialog();
}
[STAThread]
public static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Program());
}
}
class LongOp : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private int progress;
public void DoLongOp()
{
Thread thread = new Thread(new ThreadStart(this.run));
thread.Start();
}
public void run()
{
for (int i = 0; i < 10; ++i)
{
Thread.Sleep(1000);
Progress++;
}
}
public int Progress
{
get
{
return progress;
}
set
{
progress = value;
NotifyPropertyChanged("Progress");
}
}
private void NotifyPropertyChanged(String field)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(field));
}
}
}
那么如何将ProgressBar绑定到另一个线程中更新的值?
提前致谢
编辑: 我已经切换到使用Gravell先生编写并链接到的ThreadedBinding实现。我仍然得到了跨线程异常。在异常对话框中按“Break”会将PropertyChanged(this, new PropertyChangedEventArgs(field));
行突出显示为导致异常的行。
我还需要改变什么?
编辑:看起来Gravell先生的帖子已被删除。我提到的ThreadedBinding实现可以在这个帖子的末尾找到:http://groups.google.com/group/microsoft.public.dotnet.languages.csharp/browse_thread/thread/69d671cd57a2c7ab/2f078656d6f1ee1f?pli=1
我在示例中切换回普通的旧Binding,以便于其他人编译。
答案 0 :(得分:2)
不幸的是,我认为交叉线程问题会使数据绑定在这里使用有点过于笨拙,并且可能比您在任何情况下都需要更复杂 - 数据只需要以某种方式进行检测。
你可以用这样的事件处理程序替换绑定:
private void ProgressPropertyChangedHandler(object sender,
PropertyChangedEventArgs args)
{
// fetch property on event handler thread, stash copy in lambda closure
var progress = LongOp.Progress;
// now update the UI
pbProgress.Invoke(new Action(() => pbProgress.Value = progress));
}