О создании дорогих объектов WPF и многопоточности - PullRequest
1 голос
/ 30 сентября 2010

Классический совет в многопоточном программировании - выполнять процессорную работу в фоновом потоке и возвращать результат в поток пользовательского интерфейса для незначительной обработки (обновить метку и т. Д.). Что если создание самого элемента WPF является дорогостоящей операцией?

Я работаю со сторонней библиотекой, которая генерирует некоторые интенсивные элементы, рендеринг которых может занять около 0,75 с - 1,5 с. Генерация одного не так уж и плоха, но когда мне нужно создать 5 из них, чтобы показать их сразу, это заметно блокирует пользовательский интерфейс (включая счетчики прогресса). К сожалению, нет другого места для их создания, потому что WPF является аффинным потоком.

Я уже пробовал DispatcherPriority.Background, но этого недостаточно. Каков рекомендуемый способ решения этой проблемы?

1 Ответ

1 голос
/ 05 ноября 2010

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

Вы пытались создавать их по одному?Следующий пример не выполняет никакой полезной работы, но он показывает, как базовая структура выполняет большую часть работы небольшими кусочками:

int count = 100;
Action slow = null;
slow = delegate
{
    Thread.Sleep(100);
    count -= 1;
    if (count > 0)
    {
        Dispatcher.BeginInvoke(slow, DispatcherPriority.Background);
    }
};
Dispatcher.BeginInvoke(slow, DispatcherPriority.Background);

«Работа» здесь заключается в том, чтобы спать одну десятуювторой.(Таким образом, если вы замените это реальной работой, которая занимает примерно столько же времени, вы получите то же самое поведение.) Это происходит 100 раз, так что в общей сложности 10 секунд «работы».Пользовательский интерфейс остается достаточно отзывчивым в течение всего времени - такие вещи, как перетаскивание окна, становятся немного менее плавными, но его вполне можно использовать.Измените оба этих приоритета фона на «Обычный», и приложение заблокируется.

Ключевым моментом здесь является то, что мы в конечном итоге возвращаемся после выполнения каждого небольшого куска работы, ставя в очередь следующий бит - в итоге мы вызываем Dispatcher.BeginInvoke100 раз, а не один раз.Это дает UI возможность регулярно реагировать на вводимые данные.

...