2010-12-16 27 views
4

を使用している場合。クロススレッド操作ではない、私はそれに私のカスタムコントロールを持つフォームを持っていてもInvokeRequired

私は私のフォームでの方法があります。

private void SetEnabledOnControls(bool val) 
{ 
    if (InvokeRequired) 
    { 
     Invoke((Action<bool>)SetEnabledOnControls, val); 
    } 
    else 
    { 
     //do the work - iterate over child controls, 
     //and they iterate over their children, etc... 
    } 
} 

をそして私が述べた例外を取得else枝上にあるメソッド内:
Cross-thread operation not valid: Control 'txtNumber' accessed from a thread other than the thread it was created on.

私のシナリオでは、実際にはもう少し複雑です - これを例として外挿しました。実際に何が起こっているのは、私はWorkflowFoundationを使用しているということである - 私は(それ自身のスレッドで実行)WorkflowApplicationで実行されているStateMachineActivity(CTP1)を持って、私はそれのイベントにサブスクライブし、そこから私はSetEnabledOnControlsを呼んでいます。また、ブックマークを使用してワークフローを再開しています(また、サイドにMEFがあり、シナリオには関係しません)。それはInvokeRequiredがfalseの場合、私はクロススレッドの例外を持っている可能性があるか -

ことのすべては、InvokeRequiredの私の明白な誤解とは無関係ですか?私は、「手動で」コントロールを作成しません。デザイナが配置したInitialize()にすべてがあります。

誰もがこれにいくつかの光を当てることができますか?

ありがとうございます!

EDIT GWLlosaの提案を使用して、私はSystem.Threading.Thread.CurrentThread.ManagedThreadIdを使用してスレッドIDを追跡してきました。今や奇妙な部分があります... Initialize()のスレッドIDは10です。最初の2つの状態を渡す間に、Id 13 - InvokeRequiredがtrueになり、正しく呼び出されます。しかし、2番目の状態の後、SetEnabledOnControlsと入力すると再び13になりますが、今回InvokeRequiredはfalseです。どうして!?後で、もちろん、子コントロールを変更することはできません(驚くことではありません)。フォームが何とかそれが住んでいるスレッドを変更したことがありますか?

EDIT 2 今、私が呼んでいる:

if (IsHandleCreated) 
{ 
    Invoke((Action<bool>)SetEnabledOnControls, val); 
} 

、それがtrueにIsHandleCreatedを持っているが、それでもpointed atをdevSpeed何で失敗します。

EDIT 3 手のひらを顔に当てる :)状態を再開したボタンの一つは、フォームの最初のCancelButtonでした。それはのようなプロパティから削除された場合には、codebihindはまだ=それのためにキャンセルDialogResultを持っていた - ので、私のフォームが実際に閉じられ、InvokeRequiredが正しい情報を返しませんでしたので、もちろん、それはハンドルがありませんでした、ので、エラー。

ありがとうございました!今日は新しいことを学んだ:)

答えて

1

たぶん、あなたはthis problemに実行されています。

+0

実際に私はそれを最後に実行しました...有用なリンク;) – veljkoz

2

は、それはあなたがそれに触れることをしようとする直前に、あなたがコントロールが(初期化()関数内で)作成されたスレッドIDとスレッドIDをログインした場合、あなたは簡単にデバッグを行うことがあります。一般的に、私はあなたが何とかあなたが最初に期待するもの以外のスレッドでコントロールを作成したときにこれが起こるのを見ました。

+0

非常に役立つ!結果は私の更新を参照してください... – veljkoz

0

私はちょうど同じような問題に自分自身を走った、私は取り壊す機能を持っている場合は、その後、動的にFlowLayoutPanel内のコントロールを作成する:

 public static void RenderEditorInstance(DataContext dataContext, object selectedItem, Form targetForm, Control targetControl, List<DynamicUserInterface.EditorControl> editorControls, EventHandler ComboBox_SelectedIndexChanged, EventHandler TextBoxControl_TextChanged, EventHandler CheckBox_CheckChanged, EventHandler NumericUpDown_ValueChanged, CheckedListControl.ItemChecked OnItemChecked, EventHandler dateTimePicker_ValueChanged, DynamicUserInterface.DuplicationValidationFailed liveLookupValidationFailed, DynamicUserInterface.PopulateComboBoxCallback populateComboBoxCallback) 
     {   if (targetForm.InvokeRequired) 
      { 
       InstanceRenderer renderer = new InstanceRenderer(RenderEditorInstance); 
       targetForm.Invoke(renderer, dataContext, selectedItem, targetForm, targetControl, editorControls, ComboBox_SelectedIndexChanged, TextBoxControl_TextChanged, CheckBox_CheckChanged, NumericUpDown_ValueChanged, OnItemChecked, dateTimePicker_ValueChanged, liveLookupValidationFailed, populateComboBoxCallback); 
      } 
      else 
      { 
       targetControl.Padding = new Padding(2); 
       targetControl.Controls.Clear(); 

       ...{other code doing stuff here } 
      } 
     } 

し、約12本のコードが使用されていた場所の1つのインスタンスでクロススレッド例外が発生していました。このコードが使用されていたすべてのインスタンスは、「await」キーワードを使用してインターフェイス構築が非同期的に実現されるように記述されています。 GWLlosaによって行われた提案を使用して

は、私はコントロールが属するOwningThreadを取得するために、コントロールに拡張メソッドを書いた:数回の反復後にスレッドIDが実際に変更されたことを強調し..which

public static Thread OwnerThread(this Control ctrl) 
    { 
     Thread activeThread = null; 

     if (ctrl.InvokeRequired) 
     { 
      activeThread = (Thread)ctrl.Invoke(new Func<Control, Thread>(OwnerThread), new object[] { ctrl }); 
     } 
     else 
     { 
      activeThread = Thread.CurrentThread; 
     } 

     return activeThread; 
    } 

例がことを示している:明記MSDNから(https://msdn.microsoft.com/en-us/library/hh195051(v=vs.110).aspx

このコードの一部の内部に深く埋設

はTask.Run(の使用を介して、関連するコントロールを移入するデータをフェッチするために使用されるルーチンでした)非同期タスクは、方程式から取り出したメインアプリケーションスレッドTask.Run一度

()とは異なる スレッドで実行される、コントロールのスレッドは変更されません。だからあなたはそれをいつ、どのように使用するか注意する必要があります!

関連する問題