I just ran into a similar problem when I have a function tearing down and then dynamically creating controls in 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 } } } 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, 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 } } }
And in one example, around 12, where this code was used, cross-thread exceptions occurred. All instances where this code was used were written in such a way that the construction of the interface is performed asynchronously using the βwaitβ keyword.
Using the GWLlosa suggestion, I wrote an extension method for controls to get the OwningThread property that the control belongs to:
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; }
.., which emphasized that after several iterations, the thread ID really changed.
Inside this code, routines were used to retrieve the data that populated the corresponding controls using Task.Run (), which is from MSDN ( https://msdn.microsoft.com/en-us/library/hh195051(v=vs. 110) .aspx ) clearly states:
The example shows that an asynchronous task runs on a different thread than the main application thread.
After Task.Run () was deduced from the equation, the control thread has not changed. Therefore, you need to be careful how and when you use it!