WPF: как упорядочить данные для управления пользователем из другого домена - PullRequest
2 голосов
/ 26 мая 2011

Я должен использовать функциональность, которая находится в другом домене приложения.Результат должен отображаться в пользовательском элементе управления.

У меня что-то подобное:

var instance = domain.CreateInstanceFromAndUnwrap(...);
instance.Foo(myWpfUserControl as ICallback);

Foo(ICallback itf) {
   itf.SetData("...");
}

WpfUserControl.SetData(string data)
{
   if (!Dispatcher.CheckAccess())
     Dispatcher.Invoke(...)
   ...
}  

Мне пришлось поместить атрибут [Serializable] в класс WpfUserControll и реализовать конструктор сериализации, а также интерфейс ISerializableно теперь я получаю исключение:

The calling thread must be STA because many UI components require this 

, которое вызывается из конструктора UserControl ()

Что мне делать, чтобы избежать этого?Заранее спасибо !

====================================

Решение

как заметил @Al, мой пользовательский элемент управления должен быть сериализован, когда дело доходит до вызовов между приложениями.Теперь я передаю прокси, который реализует интерфейс ICallback.Прокси был помечен атрибутом Serializable.

Реализация прокси не должна иметь абсолютно никаких знаний о пользовательском контроле, поскольку должна быть предпринята попытка десериализации экземпляра пользовательского контроля еще раз.Когда я попытался абстрагировать прокси от пользовательского контроля через интерфейс, это не помогло.Когда я попытался передать интерфейс прокси (который был реализован пользовательским контролем) - произошло то же исключение.

Наконец я отделил прокси и пользовательский контроль с помощью очереди / семафоры.Очередь отслеживалась рабочим потоком, который разделял вызовы к пользовательскому элементу управления

ps, эта очередь должна быть унаследована от "MarshalByObjectRef".

1 Ответ

2 голосов
/ 26 мая 2011

Если исключение исходит от конструктора, это означает, что вы не создаете этот экземпляр элемента управления из потока пользовательского интерфейса. Это может быть хорошо, но вы должны убедиться, что Поток является потоком STA, вызвав .SetApartmentState(ApartmentState.STA) объекта потока перед запуском потока.

Это также означает, что у вас должен быть доступ к объекту потока до его запуска, поэтому вы не можете сделать это в потоке потоков.

Лучший способ избежать этой проблемы - создать элемент управления в главном потоке пользовательского интерфейса, а затем назначить текстовое значение с помощью Dispatcher (или Задачи в UiScheduler). Таким образом, вы также избежите проблем, если основной поток должен установить, получить или привязать к элементу управления, так как это вызвало бы исключение перекрестного потока, если элемент управления был создан в другом потоке

Я бы посоветовал не сериализовать контроль таким образом, если это возможно. выполнение этого приведет к созданию нового объекта, который не привязан ни к каким панелям или подобным, и исходный элемент управления не будет обновлен. к сожалению, вы не можете inheirit от MarshalByRefObject, который бы исключил сериализацию, поскольку он только передал бы ссылку на другой домен.

Если вы можете вызвать Foo отдельно, а затем передать результат в SetData в исходном домене приложения

...