Любопытно о безопасности потока управления WinForm после добавления элемента управления в отдельный поток - PullRequest
2 голосов
/ 13 июля 2010

У меня есть FileSystemWatcher, настроенный на подбор изображения, которое будет сброшено в определенный каталог. То, как я справился с этим, заключалось в добавлении PictureBox в код, закрепленный внутри панели. Я запустил его, он взорвался, и я понял, что неправильно обрабатывал взаимодействие с элементами управления в главном потоке. Вот код:

        PictureBox pb = new PictureBox();
        pnlCapturePicture.Controls.Add(pb);
        pb.Dock = DockStyle.Fill;
        pb.ImageLocation = photopath;

Теперь я понимаю, как сделать [Потокобезопасные вызовы элементов управления Windows Forms] [1], но мне любопытно, если я просто сделаю Panel Добавить поток безопасной, действительно ли я что-нибудь выполняю?

Скажи, если я сделал это:

        PictureBox pb = new PictureBox();
        AddControlThreadSafe(pb);
        pb.Dock = DockStyle.Fill;
        pb.ImageLocation = photopath;

Действительно ли взаимодействие с элементом управления PictureBox после его добавления на панель действительно поточно-ориентировано?

Ответы [ 3 ]

2 голосов
/ 13 июля 2010

Нет, это не будет работать. Ну, по крайней мере, это не будет работать последовательно. Это может работать какое-то время, но в конечном итоге он потерпит неудачу непредсказуемо и эффектно. Общее правило заключается в том, что вы ничего не можете сделать с Form или Control в каком-либо другом потоке, кроме того, в котором он был создан. Другими словами, они имеют сходство потоков. Что вам действительно нужно сделать, так это заставить основной поток пользовательского интерфейса создать и изменить PictureBox, направив в него сообщение. Это можно сделать, воспользовавшись методами ISynchronizeInvoke. Все формы и элементы управления реализуют этот интерфейс.

public void ThreadMethod()
{
  pnlCapturePicture.Invoke((Action)(() =>
  {
    PictureBox pb = new PictureBox(); 
    pnlCapturePicture.Controls.Add(pb); 
    pb.Dock = DockStyle.Fill; 
    pb.ImageLocation = photopath; 
  }));
}
2 голосов
/ 14 июля 2010

Нет, это не будет работать. Весь код GUI должен быть выполнен в соответствующем потоке пользовательского интерфейса. Контекст потока не проверяется постоянно, поэтому можно написать что-то подобное, которое будет работать сейчас, но не удастся в будущем обновлении .NET Framework.

В вашем случае FileSystemWatcher понимает шаблон ISynchronizeInvoke, поэтому просто установите его свойство SynchronizingObject в форме, с которой он работает. Обратите внимание, что если вы поместите FileSystemWatcher в форму с помощью дизайнера, это свойство будет установлено автоматически.

1 голос
/ 13 июля 2010

Установите Control :: CheckForIllegalCrossThreadCalls в true в начале программы. В этом случае каждая межпотоковая операция с Windows Forms немедленно приводит к сбою программы. Это лучше, чем неопределенное поведение по умолчанию, когда CheckForIllegalCrossThreadCalls имеет значение false.

http://msdn.microsoft.com/en-us/library/system.windows.forms.control.checkforillegalcrossthreadcalls.aspx

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