winforms: обновление прогресса с параллельным. foreach - PullRequest
0 голосов
/ 29 июня 2018

Я не видел ни одного сообщения, имеющего отношение к моей проблеме, поэтому я прошу прощения, если я отправляю уже заданный вопрос.

У меня есть программа windows form, c #, которая проверяет запасы и делает анализ. Основная форма запускает другую форму через новый поток и ShowDialog. Пока он загружается, он работает параллельно. В этом параллельном примере я хотел бы показать прогресс в основной форме.

Я столкнулся с проблемами многопоточности и добавил invoke, хотя он не кажется поточно-ориентированным, поскольку кажется, что он заходит в тупик к концу параллельного .foreach. Я пробовал делегатов, события, не повезло. Помоги мне, Оби-Ван, ты моя единственная надежда!

Урезанная версия:

Основная форма

private void button1_Click(object sender, EventArgs e)
    {
        YearLows yearLows = new YearLows();
        Thread yearLowsThread = new Thread(() => StartYearLows(yearLows));
        yearLowsThread.Start();
        btnGetYearLows.Enabled = false;
    }

    private void StartYearLows(YearLows yearLows)
    {
        yearLows.ShowDialog();
    }

    public void UpdateProgress(string text)
    {
        lblProgress.Text = text;
    }

2-й диалог формы

    public partial class YearLows : Form
    {
        private void YearLows_Load(object sender, EventArgs e)
        {
            // work
            Parallel.ForEach(responseStocks, new ParallelOptions { MaxDegreeOfParallelism = MaxThreads }, x =>
            {
              // more work
              Interlocked.Increment(stocksProcessed);
              UpdateProgress($"{stocksProcessed} / {stocksTotal} Researched");
            });
        }

        private void UpdateProgress(string text)
        {
            Invoke(new Action(() => frmMain.UpdateProgress(text)));
        }
    }

Обновление 1: Если я переместу метку обновления прогресса в дочернюю форму, то, похоже, я получаю все обновления прогресса. Мне пришлось перейти от события Load к событию Shown, чтобы форма отображалась, чтобы пользователи могли видеть обновления прогресса. Я должен был следовать совету SLaks и запустить Task.Run (() => Parallel.ForEach. Это будет работать для меня. Тем не менее, я хотел бы выяснить, почему он все еще блокируется к концу, если я хотел обновления прогресса на главной форма (я всегда читал, что async void был плохим, но я не думаю, что это можно обойти в этих сигнатурах определенных методов в winforms)

    public partial class YearLows : Form
    {
        private async void YearLows_Shown(object sender, EventArgs e)
        {
            await AnalyzeStocks();
        }

        private async Task AnalyzeStocks(object sender, EventArgs e)
        {
            // work
            await Task.Run(() => Parallel.ForEach(responseStocks, new ParallelOptions { MaxDegreeOfParallelism = MaxThreads }, x =>
            {
                // more work
                Interlocked.Increment(stocksProcessed);
                UpdateProgress($"{stocksProcessed} / {stocksTotal} Researched");
            }));
        }

        private void UpdateProgress(string text)
        {
            Invoke(new Action(() => lblProgress.UpdateProgress(text)));
        }
    }

Ответы [ 2 ]

0 голосов
/ 29 июня 2018

вы можете использовать функцию Async Await для этой куколки ... эта ссылка может быть более полезной для вас ...

зависание анимации PictureBox во время выполнения задания

0 голосов
/ 29 июня 2018

Parallel.ForEach - блокирующий вызов; он также запускает делегаты в вызывающем потоке. Поэтому пользовательский интерфейс не может обновиться, пока не завершится.

Вместо этого вы должны использовать await с Task.WhenAll (если вы выполняете асинхронную работу) или Task.Run(() => Parallel.ForEach(...)) (если он связан с процессором), чтобы вы оставляли поток пользовательского интерфейса в режиме ожидания и могли обновляться.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...