devzona
@devzona

C# многопоточность. Исключение, при доступе к Windows Forms Controls из отдельного потока, при вызове События своего класса?

Реализуется приложение в котором класс выполняет фоновую обработку задачи.
Когда требуется остановить обработку, отправляется команда на остановку.
Метод создает отдельный фоновый поток в классе, который должен дождаться остановки обработки,
и сгенерировать Событие. Когда событие выполняется, функция-обработчик в главной форме
может получить доступ к простым и сложным типап(int, List), но при попытке изменить свойство
любого элемента формы возникает исключение.
Вызывает исключение: labelStatus.Text = "Остановлен"; где labelStatus System.Windows.Forms.Label
>>>Недопустимая операция в нескольких потоках: попытка доступа к элементу управления 'labelStatus' не из того потока, в котором он был создан.
Не вызывает исключение: list.Add("S2"); где List list = new List();
Если не запускать фоновый поток, то исключение не появляется, но такой вариант не приемлем
Как решить проблему доступа к элементам, для сигнализации состояния пользователю?
Ссылка на проект:
https://yadi.sk/d/A51T1HAlgqxU2

Код листинг:
Класс ClassWithEvent
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace EventFromDifferentThread
{    
    class ClassWithEvent
    {        
        //Thread
        Thread thrStop;        
        public event EventHandler ThresholdReached;
        public ClassWithEvent()
        {            
        }

        public void Stop()
        {
            thrStop = new Thread(new ThreadStart(SubStop));
            thrStop.Start();
        }

        private void SubStop()
        {            
            //Sleep 5 Sec
            Thread.Sleep(5000);
            //Action Event
            EventArgs e = new EventArgs();
            OnThresholdReached(e);
        }

        protected virtual void OnThresholdReached(EventArgs e)
        {
            EventHandler handler = ThresholdReached;
            if (handler != null)
            {
                handler(this, e);
            }
        }
    }
}


Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace EventFromDifferentThread
{
    public partial class Form1 : Form
    {
        ClassWithEvent clsWithEvent;        
        List<string> list = new List<string>();
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            labelStatus.Text = "Остановлен";
            labelStatus.ForeColor = Color.Red;
            buttonStart.Enabled = true;
            buttonStop.Enabled = false;            
            list.Clear();
            list.Add("S1"); 
        }

        private void buttonStart_Click(object sender, EventArgs e)
        {            
            labelStatus.Text = "Работает";
            labelStatus.ForeColor = Color.Green;
            buttonStart.Enabled = false;
            buttonStop.Enabled = true;
            //Init
            clsWithEvent = new ClassWithEvent();            
            //Add Event
            clsWithEvent.ThresholdReached += frmStop;           
        }

        private void frmStop(object sender, EventArgs e)
        {            
           //здесь нет ошибки, все ок
           list.Add("S2");           
           //Здесь ошибка
           labelStatus.Text = "Остановлен";
           labelStatus.ForeColor = Color.Red;
           buttonStart.Enabled = true;
           buttonStop.Enabled = false;            
        }

        private void buttonStop_Click(object sender, EventArgs e)
        {
            //Stop
            clsWithEvent.Stop();                
        }        
    }
}
  • Вопрос задан
  • 4138 просмотров
Решения вопроса 1
devzona
@devzona Автор вопроса
Помог Как в C# реализовать изменение свойств нескольких компонентов в чужом потоке?
Требуется использовать - Invoke (исключение не вызывает)
РЕШЕНИЕ:
private void frmStop(object sender, EventArgs e)
        {            
           //здесь нет ошибки, все ок
           list.Add("S2");
           if (InvokeRequired)
           {
               Invoke(new Action(() =>
               {
                   labelStatus.Text = "Остановлен";
                   labelStatus.ForeColor = Color.Red;
                   buttonStart.Enabled = true;
                   buttonStop.Enabled = false;    
               }));
           }
           else
           {
               labelStatus.Text = "Остановлен";
               labelStatus.ForeColor = Color.Red;
               buttonStart.Enabled = true;
               buttonStop.Enabled = false;   
           }     
           ////Здесь ошибка
           //labelStatus.Text = "Остановлен";
           //labelStatus.ForeColor = Color.Red;
           //buttonStart.Enabled = true;
           //buttonStop.Enabled = false;            
        }
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 2
@vilgeforce
Раздолбай и программист
Есть хорошее правило: работать с гуем только из одного потока.
Ответ написан
Комментировать
@Oxoron
Шарпер
Для UI контролов гугли вызов Invoke.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы