When reworking the old form, I ran into a funny problem.
The task is classic: to display information about what is happening in the background to the user.
It would seem nothing complicated. In the main form, we start the flow, process data in it, and when we receive new statuses, we reset the update to the form, synchronizing with the base UI Thread (Invoke / BeginInvoke call).
')
And everything is fine until the moment when our background thread tries to create one or two more ... To which it delegates additional work as part of the task. It’s with these new streams that the leap begins ...
So, the first stream received the text for updating, we will display this text on the form.

private delegate void EditStatusTextDelegate(string strArg); private void SendNotificationToForm( string actionText ) { if (this.InvokeRequired) { this.Invoke(new EditStatusTextDelegate(UpdateUI), new object[] { actionText }); return; } UpdateUI(actionText); } private void UpdateUI(actionText) { this.LabelInfo.Text = actionText; }
or
private void SendNotificationToForm( string actionText ) { this.BeginInvoke((Action)(() => { this.LabelInfo.Text = actionText; })); }
Within one flow, it works - messages come, the form receives them, the data is updated. When we add a few more, our SendNotificationToForm function does not begin to behave exactly as expected. Messages come and get them in the form, only adds them to the queue to update the content and until your background threads finish work, do not hurry to display it. And the more challenging you are busy in other threads, the more clearly it appears. And in the real code you probably will not only need to change one Label, it is quite possible that the data set for changing the visualization will be much more complicated.

Official documentation on this topic persistently talks about InfokeRequired & BeginInvoke. But in fact, in our case, we will have to abandon the “usual method” and move on to the manual control of the synchronization context. Since we need to update occurred at the time of arrival of the data on the form, then we have to carry out "manual synchronization."
To do this - after creating the form (when the context has already been created and initialized) - remember it:
Fields: private readonly SynchronizationContext syncContext; Constructor: syncContext = SynchronizationContext.Current;
And now in our callback from another thread, execute the command:
private void SendNotificationToForm( string actionText ) { syncContext.Post( UpdateUI, actionText); } private void UpdateUI(actionText) { this.LabelInfo.Text = actionText; }
In this case, we forcedly synchronized the data for the form and forced the main UI Thread to process the received information.
From the point of view of the problem, the solution is the simplest, but effective. But it gives a guarantee that now the user will see on the form all the information from the working threads, and not just a part of the data from the first one.