Member 13479861 Ответов: 1

C# windows form TCP client cross thread operation недопустимая ошибка?


Привет,
Я тестирую приложение Tcp client C# windows form, которое может отправлять данные в программное обеспечение Tcp server(Hercules 3.2.8), но когда я отправляю данные с Tcp-сервера в windows form, то получаю следующую ошибку:

Система.InvalidOperationException: Кросс-потоковая операция недопустима: элемент управления 'MessageList' доступен из потока, отличного от потока, в котором он находился. в системе.Окна.Формы.ListBox.ObjectCollection.Добавить(элемент объекта )
в WindowsFormsAppication1.Form1.MessageCallBack(IAsyncResult ar) в From1.cs:строка 55

Строка 55 находится в Messagelist.items.Добавить(ответ);

    public partial class Form1 : Form
    {
        Socket sck;
        EndPoint remoteEp;
        byte[] buffer;
        IPAddress ip = IPAddress.Parse("192.168.42.143");
        int port = 8061;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            RemoteIptxt.Text = ip.ToString();
            Remoteporttxt.Text = port.ToString();
            //setup socket
            sck = new Socket(ip.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
            sck.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
        }

        private void Connectbtn_Click(object sender, EventArgs e)
        {
            //binding socket
            remoteEp = new IPEndPoint(IPAddress.Parse(RemoteIptxt.Text), Convert.ToInt32(Remoteporttxt.Text));
            sck.Connect(remoteEp);

            buffer = new byte[1500];
            sck.BeginReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref remoteEp, new AsyncCallback(MessageCallBack), buffer);
        }

        private void MessageCallBack(IAsyncResult ar)
        {
            try
            {
                byte[] receiveData = new byte[1500];
                receiveData = (byte[])ar.AsyncState;
                //Converting byte[] to string
                ASCIIEncoding ascencoding = new ASCIIEncoding();
                string response = ascencoding.GetString(receiveData);

                //Adding message to listbox
                MessageList.Items.Add(response);

                buffer = new byte[1500];
                sck.BeginReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref remoteEp, new AsyncCallback(MessageCallBack), buffer);
            }
            catch (Exception e)
            {
                MessageBox.Show(e.ToString());
            }
        }

        private void buttonSend_Click(object sender, EventArgs e)
        {
            //convert string message to byte[]
            ASCIIEncoding ascencoding = new ASCIIEncoding();
            byte[] sendmess = new byte[1500];
            sendmess = ascencoding.GetBytes(textMessage.Text);
            sck.Send(sendmess);
            MessageList.Items.Add("You Said:" + textMessage.Text);
            textMessage.Text = "";
        }

     
    }
}


Что я уже пробовал:

Я новичок в программировании сокетов поэтому не знаю как создать потокобезопасную программу
Пожалуйста, помогите...!!!

1 Ответов

Рейтинг:
8

OriginalGriff

Вы не можете получить доступ к любому элементу управления пользовательского интерфейса из любого потока, кроме того, в котором он был создан: поток пользовательского интерфейса (который является единственным, запущенным в начале вашего приложения). Если вы попытаетесь, то получите Кросс-потоковое исключение, как вы уже видели.

Если вы посмотрите на документацию:

Метод BeginReceiveFrom начинается асинхронно значение датаграмм без установления соединения с удаленным хостом. Вызов метода BeginReceiveFrom дает вам возможность получать данные в отдельном потоке выполнения.
Это довольно ясно показывает, что ваш метод обратного вызова выполняется в другом потоке - то есть в потоке, не относящемся к пользовательскому интерфейсу.

Чтобы получить доступ к любому элементу управления пользовательского интерфейса из метода обратного вызова, вы должны вызвать его:Контроль.Вызов Метода (Делегата) (System.Окна.Формы)[^]


Member 13479861

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

OriginalGriff

Может быть, вы хотите, чтобы я зашел и напечатал его для вас?

Member 13479861

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

OriginalGriff

Прочтите ссылку - это не сложно, и если вы собираетесь работать с потоками, вам нужно уметь это делать; вы не можете спрашивать меня каждый раз, когда вам нужна еще одна строка кода! :смеяться:

Richard Deeming

Заменять:

MessageList.Items.Add(response);

с:
Invoke((Func<string, int>)MessageList.Items.Add, response);

Member 13479861

как я могу добавить ответ к элементу управления, отличному от listbox, например Textbox/label.Я пытался
`Вызвать(Функ&ЛТ;строковые)текстовое поле textbox1.текст,ответ);`

Но это не сработало.

OriginalGriff

Читать документацию на вызова:
https://msdn.microsoft.com/en-us/library/zyzhdc6b(v=против 110).aspx
Вы вызываете элементы управления, а не строки.