Обеспечение создания дочерних элементов управления в главном потоке пользовательского интерфейса - PullRequest
0 голосов
/ 30 ноября 2011

Я изменяю существующий проект WinForms.В проекте есть UserControl.Этот UserControl имеет переменную DataSet, которая устанавливается из другой части программы в другом потоке.

Я хочу динамически добавлять другие элементы управления в этот элемент управления в зависимости от DataSet.

Итак, после загрузки DataSet, я вызываю функцию RefreshChildControl и пытаюсь добавить мои новые ChildUserControls в flowLayoutPanel.И вот тут начинаются проблемы :).Я получаю исключение «Операция между потоками недопустима: элемент управления 'ChildUserControl' доступен из потока, отличного от потока, в котором он был создан».Я пытался использовать if (this.InvokeRequired) и вызывать этот метод, но это не помогает.InvokeRequired на MyUserControl имеет значение false.

Итак, есть ли хороший способ выполнить такую ​​задачу?Или я что-то упустил?

РЕДАКТИРОВАТЬ:

Я попытался пропустить тест InvokeRequired и просто вызвать this.FindForm (). Вызвать этот метод.У меня есть «Invoke или BeginInvoke не могут быть вызваны для элемента управления, пока не будет создан дескриптор окна».исключение.И, кстати, когда я открываю другую форму с этим элементом управления, все работало нормально.

Ответы [ 2 ]

2 голосов
/ 30 ноября 2011

Во-первых.Самое простое решение - выполнять Invoke каждый раз.Ничего плохого не случится.Во-вторых, используйте SynchronizationContext.

using System.Threading;
public class YourForm
{
    SynchronizationContext sync;
    public YourForm()
    {
        sync = SynchronizationContext.Current;
        // Any time you need to update controls, call it like this:
        sync.Send(UpdateControls);
    }

    public void UpdateControls()
    {
        // Access your controls.
    }
}

SynchronizationContext решит все проблемы с потоками для вас.Он проверяет, звоните ли вы из того же или из другого потока.Если из этого же он просто сразу выполнит ваш код.В противном случае он будет вызывать Invoke через цикл сообщений формы.

1 голос
/ 12 июня 2013

Если ваш пользовательский элемент управления не сразу виден после его создания, дескриптор не будет создан в потоке, в котором вы думаете, что он создан. Это не объект C #, для которого важен родительский поток, а объект Windows Handle, родитель которого важен.

Чтобы немедленно создать элемент управления в потоке, в котором, как вы думали, вы его создали, затем прочитайте control.Handle, который заставит управление фактически быть выполненным, и назначьте дескриптор.

 MyUserControl uc = new MyUserControl(); // the handle is not created here
 uc.Visible = false;
 IntPtr dummy = uc.Handle; //  The control is immediately given a real handle

Вы также можете попытаться поиграться с uc.CreateControl, но это не создаст дескриптор, если элемент управления не виден.

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

 uc.BeginInvoke((Action)(() => uc.Text = "ha ha"));

Если вы пропустите строку dummy = uc.Handle, вы получите исключение, что вы не можете вызвать BeginInvoke для элемента управления, у которого нет дескриптора.

http://msdn.microsoft.com/en-us/library/system.windows.forms.control.createcontrol(v=vs.90).aspx

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...