2017-07-05 6 views
0

timer.Enabled状態をラップするプロパティにチェックボックスをバインドしました。他のスレッドからUIを変更しようとしたときにInvalidOperationExceptionが発生しました

のMainForm:

chbTimer.DataBindings.Add(new Binding("Checked", _inactividadController, "TimerEnabled") 
      { 
       DataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged, 
       ControlUpdateMode = ControlUpdateMode.OnPropertyChanged 
      }); 

_inactividadController:

public bool TimerEnabled 
    { 
     get { return _timer.Enabled; } 
     set 
     { 
      _timer.Enabled = value; 
      InvokePropertyChanged(new PropertyChangedEventArgs("TimerEnabled")); 
     } 
    } 

_timer.Elapsed:

private void Test(object sender, ElapsedEventArgs e) 
    { 
     TimerEnabled = false; 
    } 

例外はここに起こる:

public event PropertyChangedEventHandler PropertyChanged; 

    public void InvokePropertyChanged(PropertyChangedEventArgs e) 
    { 
     PropertyChangedEventHandler handler = PropertyChanged; 
     if (handler != null) 
        handler(this, e); //<-- BOOM 
    } 

私はここで何が起こっているのか十分に理解しています。タイマーは別のスレッドで動作し、メインスレッドにあるchbTimerを更新しようとしますが、これは不正な操作です。しかし、私はこの問題をどのように修正するかについては考えていません。

試しましたthis UIからの変更がバインディングに反映されないため(ユーザーがチェックボックスをオンにしたときにタイマーが状態を変更しないため)、アプローチは有効ですが動作しません。

提案がありますか?おかげ

+0

の実装を変更し、あなたはあなたのハンドラコードも同様に表示することはできますか。 – vendettamit

+0

UIスレッドに呼び出しをマーシャリングする必要があります。 Windowsフォームでこれを行う方法がわからない、Control.Invokeを使用する以外は、ここではうまくいきません(ハックしないでください)。 UIのスレッドでSynchronizationContextを作成して(キャプチャして)、そのSCをバインディングコードで使用しますか? – Will

+0

@vendettamitごめんなさい? 'PropertyChangedEventHandler'がそこにあります。どのハンドラを参照するのかわからない。 – Vallo

答えて

1

それはForm.cs

_inactividadController = new InactividadController(SynchronizationContext.Current); 

上のSynchronizationContext

を受けるようInactividadControllerのコンストラクタを修正し、INotifyPropertyChangedの

public void InvokePropertyChanged(PropertyChangedEventArgs e) 
    { 
     PropertyChangedEventHandler handler = PropertyChanged; 
     if (handler != null) 
     { 
      _originalContext.Post(delegate 
      { 
       handler(this, e); 
      }, null); 
     } 
    } 
+1

'SynchronizationContext'を使うと、' ThreadPool.QueueUserWorkItem'はまったく必要ありません。 –

+0

あなたが正しく編集されています – Vallo

関連する問題