The program creates and deletes objects, contains events and a method that runs in a separate thread. In this method which will work in a separate thread, this event will be triggered. In the form, you need to update the control for this event. Here is the code in a simplified form:

class class1 { //событие на которое вешается SomeEventHandler public event EventHandler event1; public class1() { new Thread(Method1).Start(); } private void Method1() { //выполняется в фоновом потоке event1?.Invoke(); } } class Form1 { SomeEventHandler() { //взаимодействие с формой //сюда нужно добавить что то, что будет взаимодействовать с формой но из основного потока } } 

As you can see, SomeEventHandler will be called in another thread, but then you cannot turn to form control in this handler. How to get around this?

The class1 constructor is also not started in the main thread, not from the interface.

  • I wrote you the answer, but I will add. In my example, class1 is Worker. You do not need to do synchronization in SomeEventHandler, but in class1 (Worker) - CasperSC

2 answers 2

An instance of the Worker class in this example should be created in the UI stream, because in its constructor we get the synchronization context.

If you don’t want to push the synchronization context into a class that contains code that works in another thread, just SomeEventHandler Invoke method inside the handler method in the window class ( SomeEventHandler )

WPF and Windows Forms different SynchronizationContext implementations. That is, depending on the technology, it redirects execution in a different way to the UI flow (if we are talking about UI ).

Notice that without

 _sycnContext = SynchronizationContext.Current ?? new SynchronizationContext(); 

The console application will not work, since SynchronizationContext.Current there will be null .

Worker.cs

 using System; using System.Threading; namespace WorkerLib { public class Worker { private readonly SynchronizationContext _syncContext; public Worker() { _syncContext = SynchronizationContext.Current ?? new SynchronizationContext(); } public event EventHandler Started; public event EventHandler Completed; private void StartOperation(object state) { _syncContext.Post(OnStarted, null); // Делаем работу Thread.Sleep(1250); _syncContext.Post(OnCompleted, null); } public void DoWork() { ThreadPool.QueueUserWorkItem(StartOperation); } private void OnCompleted(object state) { var handler = Completed; if (handler != null) handler(this, EventArgs.Empty); } private void OnStarted(object state) { var handler = Started; if (handler != null) handler(this, EventArgs.Empty); } } } 

Windows forms

MainForm.cs

 using System; using System.Windows.Forms; using WorkerLib; namespace WinForms_SyncContextExample { public partial class MainForm : Form { private readonly Worker _worker; public MainForm() { InitializeComponent(); _worker = new Worker(); _worker.Started += (sender, args) => infoLabel.Text = "Запустили работу"; _worker.Completed += (sender, args) => infoLabel.Text = "Работа завершена"; } private void WorkButton_Click(object sender, EventArgs e) { _worker.DoWork(); } } } 

Console

Program.cs

 using System; using WorkerLib; namespace SyncContextExample { internal class Program { private static void Main(string[] args) { Worker worker = new Worker(); worker.Started += (sender, args) => Console.WriteLine("Запустили работу"); worker.Completed += (sender, args) => Console.WriteLine("Работа завершена"); worker.DoWork(); Console.ReadKey(); } } } 
  • Thanks, but it doesn't work. Anyway, the event handler is not called from the main thread. The difference is that the function should be called via Thread and the form does not know who is raising the event, it passes the delegate, and there it is already added to the event. Well, the handler is not in the form of lambda. This should not affect? - shooter9688
  • The fact that I laid out 100% works. Without full code, it’s impossible to say something. So you were wrong somewhere. Throw off the code, I can see. - CasperSC
  • Lambda expressions here at all in deeds. I used them just for brevity. - CasperSC
  • Yes, it really works if you create it separately. Even added a delegate pass through another class for loyalty. Thanks, while I will not load with my code, while I myself try to find an error. - shooter9688
  • I did just like in my test project. And yes it falls out again. The first created stream "could turn to form", and the next is no longer. The bottom line is that a lot of workers. I can throw the solution, just where? - shooter9688

Create a singleton common to all threads and put an instance of your form in it. Then another thread can interact with it by reference.

However, be careful: it can happen that both flows interact with the same field at once. The solution is non-thread safe.

  • In the sense of creating an instance of class Form1? How, then, manipulations with it will affect the instance that represents the real interface? Or get a copy of the link to the form? But through what links to the instance I wouldn’t contact, there will still be a call from a non-main thread. - shooter9688
  • @ shooter9688 Get a link to the real interface and stick it where both your streams have access. - Trashbox Bobylev