Что в WPF эквивалентно Suspend/ResumeLayout() и BackgroundWorker() из Windows Forms

Если я нахожусь в функции в коде позади, и я хочу реализовать отображение "Загрузка..." в строке состояния, имеет смысл следующее, но, как мы знаем из WinForms, это NoNo:

StatusBarMessageText.Text = "Loading Configuration Settings...";            
LoadSettingsGridData();
StatusBarMessageText.Text = "Done";

Что мы все теперь знаем из WinForms Chapter 1 class 101, так это то, что форма не будет отображать изменения для пользователя до тех пор, пока не завершится вся функция... это означает, что сообщение «Загрузка» никогда не будет отображаться пользователю. Необходим следующий код.

Form1.SuspendLayout();    
StatusBarMessageText.Text = "Loading Configuration Settings...";                
Form1.ResumeLayout();

LoadSettingsGridData();

Form1.SuspendLayout();    
StatusBarMessageText.Text = "Done";
Form1.ResumeLayout();

Как лучше всего решать эту фундаментальную проблему в WPF?


person mrbradleyt    schedule 17.09.2008    source источник


Ответы (3)


Лучший и самый простой:

using(var d = Dispatcher.DisableProcessing())
{
    /* your work... Use dispacher.begininvoke... */
}

Or

IDisposable d;

try
{
    d = Dispatcher.DisableProcessing();
    /* your work... Use dispacher.begininvoke... */
} finally {
    d.Dispose();
}
person Ernest    schedule 01.08.2010
comment
Я только что добавил это в обновление DataGrid в приложении .NET 4, и это сделало обновления сетки более плавными. - person yzorg; 22.09.2010
comment
Конечно, вы хотите поместить это в using (var d = Dispatcher.DisableProcessing()), просто чтобы любые исключения не оставляли его навсегда отключенным. - person Roman Starkov; 02.01.2012
comment
Несколько опасно, так как это приостанавливает диспетчер, а не только одно окно, поэтому все операции пользовательского интерфейса будут остановлены, пока они выполняются с использованием одного и того же диспетчера. (что и все в большинстве случаев) - person Kelly; 01.06.2017

Читая статью Шона Уилдермута WPF Threads: Build More Responsive Apps With the Dispatcher< /а>.

Я наткнулся на следующее, в котором говорится, что вы можете использовать фонового рабочего так же, как в WindowsForms. Представьте, что:

BackgroundWorker Теперь, когда вы понимаете, как работает Dispatcher, вы можете быть удивлены, узнав, что в большинстве случаев вы не найдете для него применения. В Windows Forms 2.0 Microsoft представила класс для обработки потоков, не связанных с пользовательским интерфейсом, чтобы упростить модель разработки для разработчиков пользовательского интерфейса. Этот класс называется BackgroundWorker. На рис. 7 показано типичное использование класса BackgroundWorker.

Рис. 7. Использование BackgroundWorker в WPF

BackgroundWorker _backgroundWorker = new BackgroundWorker();

...

// Set up the Background Worker Events
_backgroundWorker.DoWork += _backgroundWorker_DoWork;
backgroundWorker.RunWorkerCompleted += 
    _backgroundWorker_RunWorkerCompleted;

// Run the Background Worker
_backgroundWorker.RunWorkerAsync(5000);

...

// Worker Method
void _backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
    // Do something
}

// Completed Method
void _backgroundWorker_RunWorkerCompleted(
    object sender, 
    RunWorkerCompletedEventArgs e)
{
    if (e.Cancelled)
    {
        statusText.Text = "Cancelled";
    }
    else if (e.Error != null) 
    {
        statusText.Text = "Exception Thrown";
    }
    else 
    {
        statusText.Text = "Completed";
    }
}

Компонент BackgroundWorker хорошо работает с WPF, потому что под прикрытием он использует класс AsyncOperationManager, который, в свою очередь, использует класс SynchronizationContext для работы с синхронизацией. В Windows Forms AsyncOperationManager передает класс WindowsFormsSynchronizationContext, производный от класса SynchronizationContext. Точно так же в ASP.NET он работает с другим производным SynchronizationContext, называемым AspNetSynchronizationContext. Эти производные от SynchronizationContext классы знают, как обрабатывать межпотоковую синхронизацию вызова метода.

В WPF эта модель расширена классом DispatcherSynchronizationContext. При использовании BackgroundWorker Dispatcher автоматически используется для вызова вызовов методов между потоками. Хорошая новость заключается в том, что, поскольку вы, вероятно, уже знакомы с этим распространенным шаблоном, вы можете продолжать использовать BackgroundWorker в своих новых проектах WPF.

person mrbradleyt    schedule 18.09.2008
comment
Это правда, но BackgroundWorker (threading) в данном случае не нужен. - person Martin Konicek; 15.08.2009

Самый простой способ заставить это работать — добавить LoadSettingsGridData в очередь диспетчера. Если вы установите DispatcherPriority операции достаточно низким, будут выполняться операции компоновки, и все будет готово.

StatusBarMessageText.Text = "Loading Configuration Settings...";
this.Dispatcher.BeginInvoke(new Action(LoadSettingsGridData), DispatcherPriority.Render);
this.Dispatcher.BeginInvoke(new Action(() => StatusBarMessageText.Text = "Done"), DispatcherPriority.Render);
person Abe Heidebrecht    schedule 17.09.2008