Answer the question
In order to leave comments, you need to log in
С# Taks and Invoke why is the form blocked?
Hello. I ran into a very strange problem. Namely, blocking the form even when Invoke is used. There is a conditionally form with a progress bar and two tasks from the calculation of the world. Each task is launched from its own button. Inside the task, the progress bar is called via Invoke and its counter is incremented. Conditionally, from the first task, the form is not blocked after clicking in any area, everything works as intended, but from the second task, after clicking in an arbitrary area, the form is hung up, but the progress bar goes further until the task is completed, and after completion, this click is processed as if that action has fallen into queue. I rechecked all classes and methods, nothing should block the form.
Answer the question
In order to leave comments, you need to log in
Invoke mine works synchronously with the main thread, if you put in Invoke not just updating the progress bar, but some long process, it will be blocked. Or use BeginInvoke or Invoke but only update the progress bar through it no more.
Look how I implemented the Analyzer class, write your own algorithm according to the same principle. Read the comments in the class code carefully. Read about events in C#. Write a separate class with an algorithm that generates events, and subscribe to events in the form and update the UI. Send messages from the algorithm through the synchronization context, in the algorithm do not wait for the completion of the event handler (the Post method of the thread synchronization context). Don't write all your code in form (window) event handler methods.
In the Analyzer class
, just to simulate long work.
The code below is slightly different from the code in the link.
await Task.Delay(250);
using System;
using System.Threading;
using System.Threading.Tasks;
namespace ProgressBarExample
{
internal class Analyzer
{
private readonly SynchronizationContext _synchronizationContext;
public Analyzer()
{
// Если экземпляр класса будет создан в UI потоке,
// то здесь будет контекст синхронизации UI потока, иначе пула потоков
_synchronizationContext = SynchronizationContext.Current ?? new SynchronizationContext();
}
public event EventHandler<AnalyzerEventArgs> ProgressChanged;
public Task<Data> DoWork()
{
return Task.Run(async () =>
{
for (int i = 0; i < 100; i++)
{
// Имитация долгой работы
await Task.Delay(250);
// Здесь ты можешь так же как в своём коде вызывать OnProgressChanged
// раз в несколько миллисекунд. В форме в UI потоке без Invoke обрабатывать
// событие, выводя те данные, которые ты поместишь в AnalyzerEventArgs
OnProgressChanged(new AnalyzerEventArgs("line " + (i + 1), 100));
}
return new Data() { Text = "Данные " };
});
}
private void OnProgressChanged(AnalyzerEventArgs args)
{
// Перенаправляем выполнение в UI поток не ожидая пока отработает метод обработчик события.
_synchronizationContext.Post(state =>
{
ProgressChanged?.Invoke(this, (AnalyzerEventArgs)state);
}, args); // args передаётся в переменную state (грубо говоря)
}
}
}
namespace ProgressBarExample
{
public class AnalyzerEventArgs
{
public int MaxLines { get; }
public string CurrentLine { get; }
public AnalyzerEventArgs(string currentLine, int maxLines)
{
CurrentLine = currentLine;
MaxLines = maxLines;
}
}
}
namespace ProgressBarExample
{
public class Data
{
public string Text { get; set; }
}
}
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question