WPF ProgressBar Control Dispatch по-прежнему блокирует поток пользовательского интерфейса - PullRequest
0 голосов
/ 03 марта 2011

Я использую WPF, пытаясь запустить поток в фоновом режиме, который обновляет индикатор выполнения.Я не хочу блокировать поток пользовательского интерфейса, поэтому я запускаю следующий код.Однако пользовательский интерфейс все еще заблокирован.Кажется, все так просто, что я делаю не так?

       Dispatcher.BeginInvoke(
        (ThreadStart) delegate(){                   
            for(double i = progressBar_ChangeProgress.Minimum;
                i < progressBar_ChangeProgress.Maximum;
                i++)
                {
                    for (int b = 0; b < 100000000; b++) { }
                    progressBar_ChangeProgress.Value = i;
                }
            EnableAllInputControls();
        }, DispatcherPriority.Background);

Ответы [ 3 ]

5 голосов
/ 03 марта 2011

Почему бы не использовать BackgroundWorker в этом сценарии ...

        void Go()
        {
            BackgroundWorker worker = new BackgroundWorker();
            worker.WorkerReportsProgress = true;
            worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);
            worker.DoWork += new DoWorkEventHandler(worker_DoWork);
            worker.RunWorkerAsync();
        }

        void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            progressBar_ChangeProgress.Value = e.ProgressPercentage;
        }

        void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;
            for (int b = 0; b < 100; b++) 
            {
                Thread.Sleep(100);
                worker.ReportProgress(b);
            }
        }

UPDATE:

Если вы хотите использовать Dispatcher; установите приоритет Normal и выполните обработку в фоновом потоке, а затем вызовите метод в потоке пользовательского интерфейса для предоставления обновления.

        void Go()
        {
            ThreadStart start = delegate()
            {
                //this is taking place on the background thread
                for (int i = 0; i < 100; i++)
                {
                    //this is slowing things down; no real relevance
                    Thread.Sleep(100);

                    //this will marshal us back to the UI thread
                    Dispatcher.Invoke(DispatcherPriority.Normal,
                                         new Action<int>(Update), i
                                         );
                }

            };

            new Thread(start).Start();
        }

        void Update(int value)
        {
            //this is taking place on the UI thread
            _progressBar.Value = value;
        }
2 голосов
/ 03 марта 2011

Dispatcher - это просто механизм для запуска небольшого количества кода в потоке пользовательского интерфейса в более позднее время. Приоритет, который вы передаете элементам управления , когда будет выполняться, а не какой-либо приоритет потока. В этом случае содержимое вашего делегата запускается в потоке пользовательского интерфейса. Использование BackgroundWorker, как упомянул Аарон, безусловно, поможет здесь.

Также я мог бы указать, что обычно индикатор выполнения показывает, насколько близко задание к завершению. Если вы не знаете, сколько времени потребуется, или не можете измерить прогресс, вы можете использовать индикатор неопределенности. Обновляйте значение, только если у вас есть какая-либо значимая информация. (хотя вы, возможно, только что предоставили это для демонстрационных целей)

0 голосов
/ 03 марта 2011

Все внутри BeginInvoke запускается в потоке пользовательского интерфейса и поэтому блокируется.

Что вам нужно сделать, это запустить любой интенсивный код в вашем потоке, а затем просто обновитьПользовательский интерфейс внутри Invoke.

Вы хотите что-то похожее на это:

for (double i = progressBar_ChangeProgress.Minimum;
    i < progressBar_ChangeProgress.Maximum;
    i++)
{
  for (int b = 0; b < 100000000; b++) { }
  Dispatcher.Invoke((ThreadStart) delegate(){                   
    progressBar_ChangeProgress.Value = i;
  });
}
...