Проверьте мое всестороннее исследование этой очень деликатной темы. Если вы ничего не можете сделать для улучшения фактической производительности, у вас есть следующие опции для отображения ожидающего сообщения:
Опция # 1 Выполнить код для синхронного отображения ожидающего сообщения тем же методом, который выполняет реальную задачу. Просто поместите эту строку перед длительным процессом:
Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Normal, (Action)(() => { /* Your code to display a waiting message */ }));
Он будет обрабатывать ожидающие сообщения в главном потоке диспетчера в конце Invoke () .
Примечание: Причина выбора Application.Current.Dispatcher, но Dispatcher.CurrentDispatcher объясняется здесь .
Опция # 2 Отображение экрана «Ожидание» и обновление пользовательского интерфейса (обработка ожидающих сообщений).
Для этого WinForms разработчики выполнили Application.DoEvents метод. WPF предлагает две альтернативы для достижения похожих результатов:
Опция # 2.1 С использованием Класс DispatcherFrame .
Проверьте немного громоздкий пример из MSDN :
[SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public void DoEvents()
{
DispatcherFrame frame = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, new DispatcherOperationCallback(ExitFrame), frame);
Dispatcher.PushFrame(frame);
}
public object ExitFrame(object f)
{
((DispatcherFrame)f).Continue = false;
return null;
}
Опция # 2.2 Вызов пустого действия
Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, (Action)(() => { }));
Смотрите обсуждения, какой из них (2.1 или 2.2) лучше здесь . ИМХО вариант № 1 все же лучше, чем № 2.
Опция # 3 Отображение сообщения об ожидании в отдельном окне.
Это удобно, когда вы отображаете не простое ожидающее сообщение, а анимацию. Рендеринг загрузки анимации в то время, когда мы ожидаем завершения еще одной длительной операции рендеринга, является проблемой. По сути, нам нужны два потока рендеринга. Вы не можете иметь несколько потоков рендеринга в одном окне, но вы можете поместить свою загрузочную анимацию в новое окно со своим собственным потоком рендеринга и сделать его похожим, что это не отдельное окно.
Загрузка WpfLoadingOverlay.zip из этого github (это был пример из статьи " Отзывчивость WPF: асинхронная загрузка анимаций при рендеринге ", но я могу " найти его в Интернете) или взглянуть на основную идею ниже:
public partial class LoadingOverlayWindow : Window
{
/// <summary>
/// Launches a loading window in its own UI thread and positions it over <c>overlayedElement</c>.
/// </summary>
/// <param name="overlayedElement"> An element for overlaying by the waiting form/message </param>
/// <returns> A reference to the created window </returns>
public static LoadingOverlayWindow CreateAsync(FrameworkElement overlayedElement)
{
// Get the coordinates where the loading overlay should be shown
var locationFromScreen = overlayedElement.PointToScreen(new Point(0, 0));
// Launch window in its own thread with a specific size and position
var windowThread = new Thread(() =>
{
var window = new LoadingOverlayWindow
{
Left = locationFromScreen.X,
Top = locationFromScreen.Y,
Width = overlayedElement.ActualWidth,
Height = overlayedElement.ActualHeight
};
window.Show();
window.Closed += window.OnWindowClosed;
Dispatcher.Run();
});
windowThread.SetApartmentState(ApartmentState.STA);
windowThread.Start();
// Wait until the new thread has created the window
while (windowLauncher.Window == null) {}
// The window has been created, so return a reference to it
return windowLauncher.Window;
}
public LoadingOverlayWindow()
{
InitializeComponent();
}
private void OnWindowClosed(object sender, EventArgs args)
{
Dispatcher.InvokeShutdown();
}
}