Как вы уже, наверное, поняли, вам нужно создавать каркасные объекты в потоке пользовательского интерфейса, а не в фоновом режиме.Я предполагаю, что это суть вопроса.
Это похоже на какую-то платформу плагина, в которую вводится tabContentGenerator
.Если это так, я бы использовал два действия, одно из которых выполняет долгую работу, а другое создает элементы управления.Ваш расширенный TabControl
будет запускать первый в DoWork
, а второй в WorkerCompleted
.
Например (псевдокод):
public void AddTab(Action backgroundAction, Func<FrameworkElement> constructUiAction)
{
var tab = ...
var worker = new BackgroundWorker();
worker.DoWork += (sender, e) => { backgroundAction(); };
worker.RunWorkerCompleted += (sender, e) =>
{
var ui = constructUiAction();
if (ui != null) tab.Content = ui;
};
worker.RunWorkerAsync();
}
Другой вариант -действие возвращает FrameworkElementFactory
, которое затем используется для создания экземпляра GUI в потоке пользовательского интерфейса через ControlTemplate
.FrameworkElementFactory
не является DispatcherObject
и может быть создан в потоке без GUI.Сложнее создать пользовательский интерфейс на фабриках, но если клиент указывает шаблон элемента управления в ресурсе в XAML, он может получить FrameworkFactoryElement
из его визуального дерева (например, ((ControlTemplate)FindResource("MyTemplate")).VisualTree
).
public void AddTab(Func<FrameworkElementFactory> tabContentGenerator)
{
var tab = ...
var worker = new BackgroundWorker();
FrameworkElementFactory uiFactory = null;
worker.DoWork += (sender, e) => { uiFactory = tabContentGenerator(); }
worker.RunWorkerCompleted += (sender, e) =>
{
if (uiFactory != null)
{
var template = new ControlTemplate();
template.VisualTree = uiFactory;
template.Seal();
tab.Content = template.LoadContent();
};
}
worker.RunWorkerAsync();
}