2009-04-10 47 views
4

如何将ProgressBar绑定到在另一个线程中更新的类的属性?绑定,线程和winforms

以下代码示例显示了我第一次天真的尝试。它不起作用,因为我得到有关跨线程通信的运行时错误。我想我需要以某种方式使用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绑定到另一个线程更新的值?

在此先感谢

编辑: 我转向使用ThreadedBinding实施Gravell先生题写并链接到。 虽然我仍然遇到了交叉线程异常。在例外对话框中按“Break”会突出显示PropertyChanged(this, new PropertyChangedEventArgs(field));行作为引发异常的行。

我还需要改变什么?

编辑:看起来像Mr. Gravell的帖子已被删除。我提到的ThreadedBinding实现可以在这个线程的末尾找到:http://groups.google.com/group/microsoft.public.dotnet.languages.csharp/browse_thread/thread/69d671cd57a2c7ab/2f078656d6f1ee1f?pli=1

我已经在示例中切换回普通旧Binding,以便其他人更容易编译。

回答

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

谢谢。伟大的作品:) – Tobbe 2009-04-10 22:08:20