@saneok44

С# Taks и Invoke почему то блокируется форма?

Всем привет. Столкнулся с весьма странной проблемой. А именно блокировкой формы даже когда используется Invoke. Имеется условно форма с прогресс баром и две таски с вычисления мира. Каждая таска запускается со своей кнопки. Внутри задачи через Invoke вызывается прогресс бар и его счетчик инкрементируется. Условно с первой таски форма не блокируется после клика в любую область все работает как и задумывалось, а вот со второй таски после клика в произвольную область форма вешается но прогресс бар идет дальше до завершения таски и после завершения обрабатывается этот клик как будто то действие встало в очередь. Все классы и методы перепроверил ни что не должно было блокировать форму.
  • Вопрос задан
  • 201 просмотр
Пригласить эксперта
Ответы на вопрос 2
twobomb
@twobomb
Invoke помоему синхронно работает с основным потоком, если вы в Invoke засунули не просто обновление прогресс бара,а какой-то продолжительный процесс то будет блокироваться. Или используйте BeginInvoke или Invoke но обновляйте только прогресс бар через него не более.
Ответ написан
Casper-SC
@Casper-SC
Программист (.NET)
Посмотри как я реализовал класс Analyzer, напиши свой алгоритм по такому же принципу. Внимательно прочитай комментарии в коде класса. Почитай про события в C#. Напиши отдельный класс с алгоритмом, который генерирует события, а уже в форме подпишись на события и обновляй UI. Сообщения из алгоритма отправляй через контекст синхронизации, в алгоритме не дожидайся завершения работы обработчика события (метод Post у контекста синхронизации потоков). Не пиши весь код в методах обработчиках событий форм (окон).

В классе Analyzer
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; }
    }
}


По ссылке полный код WPF приложения (не важно какой проект, в Windows Forms всё так же будет работать).
Как сделать, чтобы ProgressBar работал во время нагрузки на приложение?
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы