Почему я могу получить доступ к элементам управления из формы в потоке без исключения перекрестного потока?

Обычно, когда вы получаете доступ к элементам управления в потоке, вы получаете некоторые исключения перекрестных потоков. В моем приложении C# WinForms у меня есть окно с изображением и панель инструментов, которые не вызывают этого исключения. Я не понимаю, почему, может кто-нибудь объяснить это мне?

Вот несколько объяснений кода:

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

  • Событие1 заставляет toolstriplabel обновляться (с некоторой информацией из потока).
  • Событие2 заставляет изображение обновлять (с новым изображением из потока).

Event1 и Event2 работают отлично. Я не использую никаких методов invoke, я напрямую изменяю свойства Text и BackgroundImage без исключения перекрестных потоков.

  • Событие3, хотя и создает проблемы. Предполагается показать другую форму, но я получаю исключение crossrad. Он работает, только если я использую BeginInvoke для отображения формы.

Почему это?

<Сильный> Edit:

Многопоточность выполняется объектом MJPEGStream . Я подписываю метод NewFrame этого объекта MJPEGStream.

public partial class Form1 : Form
{
    private CAM cam;

    private PeekWindow frmPeekWindow;

    public Form1()
    {
        InitializeComponent();

        cam = new CAM();
        cam.NewImageMessageEvent += new NewImageEventHandler(cam_NewImageMessageEvent);
        cam.DetectionEvent += new DetectionEventHandler(cam_DetectionEvent);
        cam.FpsChangedMessageEvent += new FpsChangedEventHandler(cam_FpsChangedMessageEvent);
        cam.DetectionThreshold = (float)this.numDetectionThreshold.Value;

        frmPeekWindow = new PeekWindow();

       //without the next two lines, frmPeekwindow.Show() won't work if called in an event
        frmPeekWindow.Show();
        frmPeekWindow.Hide();
    }

    void cam_FpsChangedMessageEvent(object sender, FpsChangedEventArgs e)
    {
        lblFPS.Text = string.Format("fps: {0:0.0}", e.FPS);
    }

    void cam_DetectionEvent(object sender, DetectionEventArgs e)
    {
        if (chkEnablePeakWindow.Checked)
        {
            if (frmPeekWindow.InvokeRequired)
            {
                frmPeekWindow.Invoke((MethodInvoker)delegate()
                {
                    frmPeekWindow.Show();
                    frmPeekWindow.setImage(e.Image);
                });
            }
            else
            {
                frmPeekWindow.Show();
                frmPeekWindow.setImage(e.Image);
            }
        }
    }

    void cam_NewImageMessageEvent(object sender, NewImageEventArgs e)
    {
        picStream.BackgroundImage = e.Image;
    }
}

И вот класс CAM:

class CAM
{
    private object lockScale = new object();

    private MJPEGStream stream;
    private Bitmap image;

    public event NewImageEventHandler NewImageMessageEvent;
    public event FpsChangedEventHandler FpsChangedMessageEvent;
    public event DetectionEventHandler DetectionEvent;

   //configure (login, pwd, source)
    public CAM()
    {
        this.stream = new MJPEGStream("...");
        this.stream.Login = "...";
        this.stream.Password = "...";
        this.stream.NewFrame += new NewFrameEventHandler(OnNewFrame)
    }

    private void OnNewFrame(object sender, NewFrameEventArgs ev)
    {
        try
        {
            FpsChangedMessageEvent(this, new FpsChangedEventArgs(10));

           //get image
            image = ev.Frame;
            NewImageMessageEvent(this, new NewImageEventArgs(new Bitmap(image)));

            DetectionEvent(this, new DetectionEventArgs(new Bitmap(image)));
        }
        catch (Exception ex)
        {
            Console.Out.WriteLine(ex.Message);
        }
    }
}
0
nl ja de
Как вы делаете многопоточность?
добавлено автор Dave Bish, источник
События! = Темы. Можете ли вы показать нам какой-то код?
добавлено автор Simon Whitehead, источник
События! = Темы. Можете ли вы показать нам какой-то код?
добавлено автор Simon Whitehead, источник
События! = Темы. Можете ли вы показать нам какой-то код?
добавлено автор Simon Whitehead, источник

4 ответы

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

See the following explanation from Microsoft. http://msdn.microsoft.com/en-us/library/ms171728.aspx

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

1
добавлено
его почти совпадение, что это сработало для вас. Все зависит от того, как инициируется событие, находится ли он на переднем плане или фоновом потоке, и вы не можете полагаться на его согласованность.
добавлено автор Keith, источник
Поэтому лучше всего будет, используя комбинацию InvokeRequired/Invoke во всем мире, задействован поток и элемент управления. Это совпадение, что он работает здесь без, и я не должен полагаться на это?
добавлено автор user1806262, источник

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

See the following explanation from Microsoft. http://msdn.microsoft.com/en-us/library/ms171728.aspx

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

1
добавлено
его почти совпадение, что это сработало для вас. Все зависит от того, как инициируется событие, находится ли он на переднем плане или фоновом потоке, и вы не можете полагаться на его согласованность.
добавлено автор Keith, источник
Поэтому лучше всего будет, используя комбинацию InvokeRequired/Invoke во всем мире, задействован поток и элемент управления. Это совпадение, что он работает здесь без, и я не должен полагаться на это?
добавлено автор user1806262, источник

Вам необязательно всегда вызывать BeginInvoke/Invoke. Иногда операция выполняется на переднем плане, иногда она находится в фоновом режиме.

По образцам microsoft, которые повсюду, вы можете СЛЕДУЕТ проверить, требуется ли вызов BeginInvoke/Invoke.

private void SetTextStandardPattern()
{
    if (this.InvokeRequired)
    {
        this.Invoke(SetTextStandardPattern);
        return;
    }
    this.text = "New Text";
}

Here is a nice microsoft article that has a sample: http://msdn.microsoft.com/en-us/library/ms171728(v=vs.80).aspx

and here is another article on how to "avoid" the pattern: http://www.codeproject.com/Articles/37642/Avoiding-InvokeRequired

0
добавлено

У меня есть три возможности:

  1. Действие уже отправлено в поток gui.
  2. Действие не нужно отправлять в настоящее время.
  3. Действие выполняется каким-то образом из потока gui.

Это, скорее всего, номер 3.

0
добавлено
В этом случае свойство BackgroundImage просто не заботится в каждом случае. Но посмотрите на этот похожий вопрос: stackoverflow.com/questions/6527825/…
добавлено автор Andre, источник
вы имеете в виду, например, «picStream.BackgroundImage = e.Image;» по какой-то причине запускается из потока GUI? Я проверил с помощью «picStream.InvokeRequired», и он возвращает «True». Другими словами: требуется (код работает на потоке без GUI), но не имеет значения, что я не использую Invoke.
добавлено автор user1806262, источник
Microsoft Stack Jobs
Microsoft Stack Jobs
1 788 участник(ов)

Work & freelance only Microsoft Stack. Feed https://t.me/Microsoftstackjobsfeed Чат про F#: @Fsharp_chat Чат про C#: @CSharpChat Чат про Xamarin: @xamarin_russia Чат общения:@dotnettalks

Microsoft Developer Community Chat
Microsoft Developer Community Chat
584 участник(ов)

Чат для разработчиков и системных администраторов Microsoft Developer Community. __________ Новостной канал: @msdevru __________ Баним за: оскорбления, мат, рекламу, флуд, флейм, спам, NSFW контент, а также большое количество оффтоп тем. @banofbot