Помощь, необходимая для «ошибки операции с несколькими потоками» в C # - PullRequest
1 голос
/ 03 марта 2009

В следующем коде MessageReceived находится в потоке, отличном от label1, и при попытке доступа к нему я получу эту ошибку:

Поперечная операция не действительна: Элемент управления «label1» доступен из нить, кроме нити это было создан на.

foo.MessageReceived += new Agent.MessageReceivedHandler(foo_MessageReceived); 

void foo_MessageReceived(Message message)
{
   label1.Text = message.Body;
}    

Как я могу решить эту проблему?

Подробнее : очевидно, мне нужно использовать delegate и invoke, но я не знаю как, не могли бы вы объяснить подробнее?

Ответы [ 6 ]

4 голосов
/ 03 марта 2009

Надеюсь, это будет закрыто как точный дубликат, но если нет:

Не трогайте GUI из потока, не являющегося GUI. Используйте BackgroundWorker и соответствующим образом сообщайте о прогрессе или читайте страницу WinForms моей статьи о потоках для более прямого контроля (Control.Invoke / BeginInvoke).

1 голос
/ 03 марта 2009

Вам необходимо использовать Control.Invoke (или Control.BeginInvoke). Сначала создайте новое приложение Windows Forms, добавьте метку и кнопку. Дважды щелкните кнопку в Visual Studio, чтобы отредактировать событие Click и добавить следующий код:

    private void button1_Click(object sender, EventArgs e)
    {
        new System.Threading.Thread(new System.Threading.ThreadStart(Run)).Start();
    }

    void Run()
    {
        label1.Invoke(new Action(delegate()
        {
            label1.Text = System.Threading.Thread.CurrentThread.Name + " " + System.DateTime.Now.ToString();
        }));
    }
1 голос
/ 03 марта 2009

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

0 голосов
/ 03 марта 2009

Убедитесь, что вы обновляете свой GUI в основном потоке (поток GUI).

foo.MessageReceived + = новый Agent.MessageReceivedHandler (foo_MessageReceived);

public delegate void MyDelegate(Message msg);
void foo_MessageReceived(Message message)
{ 
   if (InvokeRequired)
   {
      BeginInvoke(new MyDelegate(foo_MessageReceived),new object[]{message});
   }
   else
   {
      label1.Text = message.Body;
   }
}
0 голосов
/ 03 марта 2009

В вашем классе Агента, когда вы вызываете событие MessageReceived, вам нужно проверить, реализует ли объект-обработчик события ISynchronizeInvoke. Если это так, и если свойство InvokeRequired возвращает true, вам придется вызвать обработчик событий.

Если вы используете не WinForms, а WPF, вы больше не можете полагаться на ISynchronizeInvoke, так как элементы управления WPF не реализуют этот интерфейс. Вместо этого вам придется работать с AsyncOperation и AsyncOperatoinManager.

0 голосов
/ 03 марта 2009

Это совершенно не полезно. Я бы хотел проголосовать сам.

Возможно, я устарел, но из того, что я помню, вам не разрешено изменять в GUI что-либо, кроме основного потока.

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