Каковы проблемы с запуском WPF в нескольких доменах приложений в одном потоке пользовательского интерфейса?
Мы планируем создать пользовательский интерфейс WPF, работающий в нескольких доменах приложений. Один из доменов приложений будет запускать приложение, а остальные домены приложений будут содержать ряд пользовательских элементов управления и логики. Идея, конечно же, состоит в том, чтобы изолировать эти пользовательские элементы управления и логику от основного приложения.
Вот пример использования MAF / System.AddIn. Какой опыт у других был с этим? Как это решение обрабатывает RoutedEvents / Commands, которые могут возникать внутри одного пользовательского элемента управления, и правильно ли они сериализуются в доменах приложений? А как насчет ресурсов WPF? Можно ли легко получить к ним доступ через домены приложений?
Ответов (2)2
Я ответил на аналогичный вопрос здесь и также отредактировал его для WPF, вы можете использовать интересное свойство того, как работает механизм компиляции, чтобы прикрыть диспетчерский насос в одном из контекстов рендеринга. Это действительно легкий вариант.
Кроме того, я полагаю, вы знаете о корпоративной библиотеке и единстве?
Есть блок приложения WPF, так что использование этого шаблона не слишком болезненно;) Но разве они не говорят: «Нет боли - нет выигрыша»?
Также существует CAB (Composite UI Application Block), объединяющий в единое целое. Люди из WPF SDK создали платформу Silverlight и WPF. (он же Призма).
Ах да, еще вы спросили о ресурсах? Я предпочитаю загружать ресурсы вручную в классе Application. Я понял одну вещь: допустим, у вас есть ResourceDictionary в подпапке, и вы загружаете MergedDictionaries в этот ResourceDictionary. Итак, если в вашем классе Application вы загружаете «my-res-dir / MergedDictionaryLoader.xaml» (по коду или xaml), ВСЕ БУДУЩИЕ ЗАГРУЗКИ MERGEDDICTIONARIES загружаются из «my-res-dir».
Какое-то безумие, если вы спросите меня, я бы подумал, что, поскольку текущий каталог процесса не изменился, вы должны указать "my-res-dir / foo.xaml" для всех ваших дополнительных каталогов. Однако это не так (я не верю, что это где-то задокументировано, по крайней мере, очень хорошо и должно считаться ошибкой, imho).
Так что помните, что загрузка словаря ресурсов WPF будет происходить из каталога, в котором находится текущий XAML . Таким образом, вы указываете Source = "foo.xaml" из вашего "my-res-dir / MergedDictionaryLoader.xaml". Я даже играл с синтаксисом URI pack / absolute, но никогда не находил, что это будет намного более интуитивно понятным.
Старый вопрос, но тем не менее: вам понадобится несколько потоков пользовательского интерфейса - по одному на каждый домен приложения. Создайте их так:
var thread = new Thread(() =>
{
var app = new Application();
app.Run();
});
thread.Name = AppDomain.CurrentDomain.FriendlyName;
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
Самая большая проблема заключается в том, что вы не можете отправлять FrameworkElements между доменами приложений (они не являются MarshalByRefObject), но вы можете использовать методы FrameworkElementAdapters.ViewToContractAdapter () и ContractAdapterToView (), чтобы обойти это ограничение. Дополнительные сведения см. На странице MSDN FrameworkElementAdapters .
Затем, как только вы это сделаете, самая большая проблема, ИМХО, заключается в том, что вы не можете положить что-либо поверх FrameworkElement из «удаленного» домена (классическая «проблема с воздушным пространством»). См. Эту ветку для получения дополнительной информации об этом.