Нужна помощь в получении информации через поток пользовательского интерфейса и другой поток в C #
-
04-07-2019 - |
Вопрос
У меня есть серверное приложение, которое получает информацию по сети и обрабатывает ее. Сервер является многопоточным и обрабатывает несколько сокетов одновременно, а потоки создаются без моего контроля с помощью методов стиля BeginInvoke и EndInvoke, которые связаны соответствующими функциями обратного вызова.
Я пытаюсь создать форму, в дополнение к основному графическому интерфейсу, которая отображает элемент ListBox, заполненный элементами, описывающими подключенные в данный момент сокеты. Итак, в основном я пытаюсь добавить элемент в ListBox с помощью функции Add () из потока, в котором выполняется соответствующая функция обратного вызова. Я получаю доступ к своим элементам управления формами через свойство Controls - I.E:
(ListBox)c.Controls["listBox1"].Items.Add();
Естественно, я не просто вызываю функцию, я пробовал несколько способов, которые я нашел здесь и в Интернете, для связи между потоками, включая MethodInvoker
, используя делегат
, в сочетании с Invoke ()
, BeginInvoke ()
и т. д.
Кажется, ничего не работает, я всегда получаю одно и то же исключение, сообщающее, что к моему элементу управления был получен доступ из потока, отличного от того, в котором он был создан.
Есть мысли?
Решение
Вы должны вызвать Invoke (или BeginInvoke) для элемента управления ListBox, к которому вы обращаетесь, для вызова делегата в потоке, создавшем этот элемент управления.
ListBox listBox = c.Controls["listBox1"] as ListBox;
if(listBox != null)
{
listBox.Invoke(...);
}
Другие советы
Я всегда использовал что-то вроде этого:
c = <your control>
if (c.InvokeRequired)
{
c.BeginInvoke((MethodInvoker)delegate
{
//do something with c
});
}
else
{
//do something with c
}
Я также написал несколько вспомогательных методов расширения, чтобы ... помочь.
using System;
using System.ComponentModel;
public static class CrossThreadHelper
{
public static bool CrossThread<T,R>(this ISynchronizeInvoke value, Action<T, R> action, T sender, R e)
{
if (value.InvokeRequired)
{
value.BeginInvoke(action, new object[] { sender, e });
}
return value.InvokeRequired;
}
}
используется так:
private void OnServerMessageReceived(object sender, ClientStateArgs e)
{
if (this.CrossThread((se, ev) => OnServerMessageReceived(se, ev), sender, e)) return;
this.statusTextBox.Text += string.Format("Message Received From: {0}\r\n", e.ClientState);
}
Использование BeginInvoke или Invoke должно работать нормально. Не могли бы вы опубликовать короткую, но полную программу, которая демонстрирует проблему? Вы должны быть в состоянии работать над тем, что на самом деле не требует каких-либо вещей на стороне сервера - просто есть куча потоков, которые "притворяются" получать входящие соединения.