2009-04-10 10 views
4

ProgressBarを別のスレッドで更新されたクラスのプロパティにバインドするにはどうすればよいですか?バインディング、スレッド、およびwinforms

次のコード例は、初めての試みです。私はスレッド間通信に関するランタイムエラーが発生するため、動作しません。私は何らかの方法でInvokeを使用する必要があると思いますが、Bindingクラスを使用してInvokeを実行する方法がわかりません。

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を別のスレッドで更新された値にバインドするにはどうすればよいですか?事前に

おかげ

EDIT: 私は氏Gravellが書いたとにリンクされているThreadedBindingの実装を使用してに切り替えました。 私はまだクロススレッド例外を取得しています。例外ダイアログで "Break"を押すと、例外の原因となった行としてPropertyChanged(this, new PropertyChangedEventArgs(field));行が強調表示されます。

さらに何を変更する必要がありますか?

編集: Gravell氏の投稿が削除されたようです。 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

関連する問題