Межпоточная операция недопустима при использовании Invoke

Я создал систему чата и получил такую ​​ошибку:

Межпоточная операция недопустима: MessageBox и т. Д.

Что я сделал: я добавил вызов. Вот код:

Invoke(new Action(() => messageBox.Items.Add(usersName.Text + ": " + receivedMessage)));

Проблема в том, что он в основном отправляет сообщение от другого пользователя, которое пусто. Это потому, что я подключен к чату локально. Вот картинка:

Приложение чата

Получение сообщений:

private void MessageCallBack(IAsyncResult aResult)
{
    try
    {
        byte[] receivedData = new byte[1500];
        receivedData = (byte[])aResult.AsyncState;
        ASCIIEncoding aEncoding = new ASCIIEncoding();
        string receivedMessage = aEncoding.GetString(receivedData);
        Invoke(new Action(() => messageBox.Items.Add(usersName.Text + ": " + receivedMessage)));
        buffer = new byte[1500];
        socket.BeginReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref theirIp, new AsyncCallback(MessageCallBack), buffer);
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

Отправка сообщений:

private void sendBtn_Click(object sender, EventArgs e)
{
    try
    {
        if (messageTb.Text == "")
        {
            return;
        }
        else
        {
            ASCIIEncoding eEncoding = new ASCIIEncoding();
            byte[] msg = new byte[1500];
            msg = eEncoding.GetBytes(messageTb.Text);
            socket.Send(msg);
            messageBox.Items.Add(yourName.Text + ": " + messageTb.Text);
            messageTb.Clear();
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
    this.ActiveControl = messageTb;
}

person Richard Jacobs    schedule 05.02.2016    source источник


Ответы (2)


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

Я использую следующий простой механизм журнала, он подходит только для простого приложения.

private delegate void LogDelegate(ListBox messageBox, string data);

private LogDelegate _logDelegate;
private void Log(ListBox messageBox, string data)
{
    if (messageBox.InvokeRequired)
    {
        LogDelegate logDelegate = Log;
        Invoke(logDelegate, messageBox, data);
    }
    else
    {
        messageBox.Items.Add(data);
    }
}

public Form1()
{
    InitializeComponent();
    //don't forget, initialize the delegate
    _logDelegate = Log;
}

private void btn_Start_Click(object sender, EventArgs e)
{
    Log("Anything to log");
}
private void MessageCallBack(IAsyncResult aResult)
{
    try
    {
        //Instead of Invoke use 
        //Invoke(new Action(() => messageBox.Items.Add(usersName.Text + ": " + receivedMessage)));
        Log("Anything to log");

    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

Как я уже сказал, код можно использовать где угодно и он прост. Но для более сложного механизма ведения журнала и повышения производительности используйте Log4Net или NLog.

person Bewar Salah    schedule 05.02.2016
comment
Спасибо за ваш комментарий. С удовольствием сработало! Единственное ... он оставляет пустое место после каждого сообщения: / Он просто удалил другой комментарий. Какие-либо предложения? Еще раз спасибо! - Ричард - person Richard Jacobs; 05.02.2016
comment
Мне доставляет удовольствие помогать другим. Я использую этот код для входа в TextBoxes, а не ListBoxes, и он работает хорошо. Пожалуйста, не могли бы вы написать код и показать, как вы его реализуете? - person Bewar Salah; 05.02.2016
comment
Большое спасибо за терпение. - person Richard Jacobs; 05.02.2016
comment
Я проверил код и ничего не нашел. Но можешь ли ты сделать что-нибудь? Если вы установите точку останова и перейдете в режим отладчика и увидите строку ReceiveMessage = aEncoding.GetString (gotData); какие данные находятся в ReceiveMessage? - person Bewar Salah; 05.02.2016

Если значение переменной receivedMessage изменится до выполнения вызванного действия, будет использовано новое значение этой переменной - если оно работает так же, как ваш пример messageTb.Text, значение будет немедленно очищено, и вызванное действие увидит только после очистки пустое значение. Попробуйте скопировать строку usersName.Text + ": " + receivedMessage в одноразовую переменную и сослаться на нее в своем Invoke, например

string newMessage = usersName.Text + ": " + receivedMessage;
Invoke(new Action(() => messageBox.Items.Add(newMessage)));
person FacticiusVir    schedule 05.02.2016
comment
Спасибо за ответ, но, к сожалению, это не сработало. Большое спасибо за объяснение. Я еще раз посмотрю. - Ричард - person Richard Jacobs; 05.02.2016