Вопрос по multithreading, .net – Создание элементов управления в потоке без пользовательского интерфейса

7

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

<code>Activator.CreateInstanceFrom(dllpath, classname).
</code>

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

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

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

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

"пока я не попытаюсь установить какое-либо свойство" - это в ветке или позже? Henk Holterman
Это позже, после того, как пользовательский элемент управления был перенесен в основную форму (как в form.controls.add (mycontrol)) Tom Juergens

Ваш Ответ

3   ответа
1

этот ответ предоставляет элегантный способ обойти эту проблему.

Код цитируется из этого ответа:

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;
    });        
}
Я пока не понимаю, как это поможет. Я имею в виду, да, вы правы, конечно, использование Invoke / BeginInvoke поможет, но это именно то, чего я пытаюсь избежать. Или, может быть, я просто не поняла, к чему ты клонишь. Tom Juergens
Если вы создаете элементы управления в потоке, отличном от потока пользовательского интерфейса, я не могу понять, как вы отойдете от Invoke / BeginInvoke. Однако предлагаемый код намного проще, чем вариант if (ctl.InvokeRequired) [...]. Немедленное наказание за многопоточность - это то, что вам нужно выполнить синхронизацию;) Fredrik Mörk
3

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

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

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

Да, у меня такое чувство, что я пытаюсь быть слишком умным. Я более или менее отказался от своей первой попытки и двигаюсь по линиям, аналогичным вашему второму абзацу. Спасибо за советы в пар. 3; Я этого не понял. Tom Juergens
Лично я предпочитаю использовать очередь Msdn.microsoft.com / EN-US / библиотека / 7977ey2c.aspx) для связи между потоками: фоновый поток добавляет элементы («результаты») в очередь, поток пользовательского интерфейса проверяет очередь на холостом ходу и обновляет элементы управления (это типичный производитель / потребитель). Но вы должны тщательно обдумать, если фон не может опередить способность пользовательского интерфейса идти в ногу, что может легко произойти, особенно с сетками, из-за чего очередь выйдет из-под контроля, если вы не примете специальные мер Remus Rusanu
1

я немного поэкспериментировал, и на деле вы можете установить большинство свойств в потоке, если он не был парентирован (т.е. добавлен в какое-либо свойство Control.Controls).

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

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

Это было ясно, но я делаю это без проблем. Henk Holterman
Да, кажется, что родители убивают меня. Ваша идея не так уж плоха, но здесь она не поможет, так как все свойства, которые я устанавливаю, являются реакцией на какое-то взаимодействие с пользователем, другими словами,посл элемент управления был перенесен в основную форму и отображен. Возможно, это не совсем понятно из моего вопроса. Tom Juergens

Похожие вопросы