2009-06-24 2 views
7

у меня есть своего рода вставной модели, в которой различные сложные пользовательские элементы управления хранятся в DLL, и загружен и инстанцированный во время выполнения с помощьюСоздание элементов управления в не-UI нить

Activator.CreateInstanceFrom(dllpath, classname). 

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

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

Итак, мой вопрос: существует ли какой-либо безопасный способ делать то, что я пытаюсь, или как лучше всего загружать эти элементы управления в фоновом режиме? Или это в принципе невозможно, и я должен придерживаться основного потока для создания элементов управления?

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

+0

«пока я не попытаюсь установить какое-либо свойство» - это в теме или позже? –

+0

Это позже, после того, как пользовательский элемент управления был включен в основную форму (как в form.controls.add (mycontrol)) –

ответ

3

Прекрасно загружать библиотеки DLL и создавать объекты управления в фоновом режиме, но элемент управления должен быть добавлен к форме в основном потоке и всем взаимодействии с пользователем, а также при любом программном изменении свойств управления (после того, как он был создано) должно происходить в основном потоке. Об этом просто нет, как вы, наверное, уже знаете. Теперь, если загрузка этих DLL и создание элементов управления возрастает, я не вижу причин делать это в отдельных потоках фона.

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

Попытка сделать родовое один подходит для всех рамок, которая работает одинаково в режиме потока UI и в фоновом режиме и просто проверяет результаты InvokeRequired иногда хуже производительности (так как все потоки блокируются в Invoke) или даже в (незаметных) взаимоблокировках, как только приложение достигнет разумной сложности. Кроме того, все обновления async в BeginInvoke, без учета каждого метода в отдельности, могут привести к проблемам согласованности данных (т. Е. Элементы управления могут обновлять себя до состояний назад во времени из-за изменения порядка вызова между потоками).

+0

Да, у меня такое чувство, что я пытался быть слишком умным. Я более или менее отказался от своей первой попытки и двигаюсь вдоль линий, похожих на ваш второй абзац. Спасибо за советы в пар. 3; Я этого не осознавал. –

+0

Лично я предпочитаю использовать очередь (http://msdn.microsoft.com/en-us/library/7977ey2c.aspx) для связи между потоками: фоновый поток добавляет элементы («результаты») в очередь, Поток пользовательского интерфейса проверяет очередь на Idle и обновляет элементы управления (это типичный производитель/потребитель). Но вы должны тщательно рассмотреть, если фон не может опередить возможности пользовательского интерфейса, которые могут быть легко реализованы, особенно с сетками, в результате чего очередь будет выходить из-под контроля, если вы не примете специальные меры. –

1

Образец кода в this answer обеспечивает элегантный способ решения этой проблемы.

Код процитировано из этого ответа:

public void UpdateTestBox(string newText) 
{ 
    BeginInvoke((MethodInvoker) delegate { 
     tb_output.Text = newText; 
    });   
} 

... хотя в вашем случае, если вы хотели бы вызвать BeginInvoke на самих элементов управления:

public void UpdateTestBox(string newText) 
{ 
    tb_output.BeginInvoke((MethodInvoker) delegate { 
     tb_output.Text = newText; 
    });   
} 
+0

Я пока не совсем понимаю, как это поможет. Я имею в виду, да, вы правы, конечно, использование Invoke/BeginInvoke поможет, но это именно то, чего я пытаюсь избежать. Или, может быть, я просто не понял, к чему вы клоните. –

+1

Если вы создаете элементы управления в другом потоке, кроме потока пользовательского интерфейса, я не вижу, как вы уберетесь от Invoke/BeginInvoke. Однако предлагаемый код намного проще, чем вариант if (ctl.InvokeRequired) [...]. Немедленное наказание за многопоточность заключается в том, что вам нужно выполнить вашу синхронизацию;) –

1

Не зная деталей механизма InvokeRequired , Я немного экспериментировал, а afaik вы можете установить большинство свойств в Thread, если он не был Parented (т.е. добавлен в какое-либо свойство Control.Controls).

Итак, вы должны иметь возможность подготовить свои элементы управления, сохранить их в списке и прикрепить их к основному интерфейсу в методе Invoked.


Редактировать: Я не думаю, что это важно, какая тема создала элемент управления. Поэтому должны применяться нормальные правила, т. Е. Вы можете работать только с элементами управления, образующими основной поток Windows. И я считаю, что критерием является HandleCreated, а не Parented. Пока этого не произошло, вы немного передохните.

+0

Да, кажется, что воспитание - это то, что меня убило. Ваша идея не так уж плоха, но здесь это не поможет, так как свойства, которые я устанавливаю, - это все в ответ на какое-то взаимодействие с пользователем, другими словами * после * элемент управления был помещен в основную форму и отображен. Возможно, это не совсем ясно из моего вопроса. –

+0

Было ясно, но я делаю это без проблем. –

Смежные вопросы