none
Доступ к элементам формы из потока RRS feed

  • Вопрос

  • Добрый день
    В приложении wpf .net 451 есть задача запустить в фоне несколько процессов, каждый из которых обращается  к элементам формы и заполняет их. Для первичной реализации использовалась пара async-await. При этом всё работает.
    Если использовать создание потоков посредством Parallel.For, то интерфейс пользователя почему-то блокируется и не особождается, пока все процессы не закончат работу.
    Как это решить?

    Вот создание потоков:

    Parallel.For(0, CountClient, i =>
    {
      StartClient(i);
    });

    или

    Parallel.For(0, CountClient, async i =>
    {
      await StartClientAsync(i);
    });

    Вот обращение к элементам формы:
    this.gridRun.Dispatcher.BeginInvoke((Action)(() =>
    {
    }
    ));

    или

    await this.gridRun.Dispatcher.BeginInvoke((Action)(() =>
    {
    }
    ));

    16 апреля 2014 г. 16:42

Ответы

  • В методе Dispatcher.Invoke следует выполнять лишь короткую операцию, связанную непосредственно с UI. То есть нужно поместить его внутрь цикла, а в него - обновление прогрессбара. Thread.Sleep при этом должен быть вне Invoke.
    17 апреля 2014 г. 10:35

Все ответы

  • 1. async/await, применённые к анонимному методу, не оказывают никакого эффекта, т.к. ожидается завершение вызова Parallel.For, а не анонимного метода.

    2. Вызов Parallel.For синхронный, это значит, что он в целях производительности использует не только пул потоков, но и текущий поток, из которого он был вызван.

    Parallel.For не поддерживает async/await, но можно запустить его в отдельном таске и уже дожидаться его завершения.

    await Task.Run(() => Parallel.For(0, CountClient, i =>
    {
      StartClient(i);
    }));

    • Предложено в качестве ответа Sing1e 16 апреля 2014 г. 17:57
    16 апреля 2014 г. 17:56
  • Спасибо, я так уже пробовал.

    Не получилось:(

    Есть ещё варианты?

    17 апреля 2014 г. 7:24
  • Я приведу код, в котором возникает блокировка UI.
    На форме wpf (.net 451) два элемента ProgressBar: pb1 и pb2.

    Как избежать блокировки UI?
    ---------------------------------------------------
    private void btStart_Click(object sender, RoutedEventArgs e)
    {
      Task.Run(() =>
      {
        Parallel.Invoke(

        //Start first task
        () =>
        {
          this.gridRun.Dispatcher.Invoke((Action)(() =>
          {
            for (int i = 0; i < 100; i++)
            {
              pb1.Value++;  //ProgressBar 1
              Thread.Sleep(50); //Эмуляция работы
            }
          }
          ));
        },

        //Start second task
        () =>
        {
          this.gridRun.Dispatcher.Invoke((Action)(() =>
          {
            for (int i = 0; i < 100; i++)
            {
              pb2.Value++; //ProgressBar 2
              Thread.Sleep(50); //Эмуляция работы
            }
          }
          ));
        }       
       
        );
      }
      );
    }
    ---------------------------------------------------

    17 апреля 2014 г. 10:04
  • В методе Dispatcher.Invoke следует выполнять лишь короткую операцию, связанную непосредственно с UI. То есть нужно поместить его внутрь цикла, а в него - обновление прогрессбара. Thread.Sleep при этом должен быть вне Invoke.
    17 апреля 2014 г. 10:35
  • Да! Я только это понял и всё получилось.

    Спасибо, оказалось наши решения совпали.

    17 апреля 2014 г. 11:34