Я написал асинхронные классы клиент / сервер, которые прекрасно работают в консоли.Я создал проект WinForm для сервера, который подписывается на событие, генерируемое сервером при наличии соединения .Pending()
, и записывает некоторые сообщения в текстовое поле, что вызывает исключение Cross-Thread.Исключение не удивляет меня, однако я ищу способ вызвать это событие, не вызывая этого исключения, не обрабатывая его в GUI / Control с помощью .InvokeRequired
и .Invoke
- если это вообще возможно?
Сервер запускается следующим образом:
Server server = new Server(PORT);
server.RunAsync();
в .RunAsync()
Я просто перебираю сетевые устройства и настраиваю их на прослушивание и вызывает событие, запущенное сервером, это также записывается в графический интерфейсоднако без каких-либо проблем.
public async Task RunAsync()
{
GetNetworkDevicesReady(Port);
await Task.Factory.StartNew(() =>
{
Parallel.ForEach(networkListeners, (listener) =>
{
Write.Info($"LISTENING ON {listener.LocalEndpoint}");
listener.Start();
});
});
IsRunning = true;
OnServerStarted?.Invoke(this, networkListeners.Where(l=>l.Active).ToList());
}
Приведенный ниже код зарегистрирован в событии Form.Load
и не вызывает исключение Cross-Thread при записи «SERVER STARTED» в текстовое поле.
server.OnServerStarted += (s, a) =>
{
consoleWindow1.Event("SERVER STARTED", $"{Environment.NewLine}\t{string.Join($"{Environment.NewLine}\t", a.Select(x=>x.LocalEndpoint))}");
consoleWindow1.Event("WAITING FOR PENDING CONNECTIONS");
server.WaitForConnectionsAsync();
};
И этот код работает неопределенно долго, пока не сработает токен отмены:
public async Task WaitForConnectionsAsync()
{
waitingForConnectionsToken = new CancellationTokenSource();
await (waitinfConnectionTaks=Task.Factory.StartNew(async () =>
{
while (!waitingForConnectionsToken.IsCancellationRequested)
{
foreach (var listener in networkListeners)
{
if (waitingForConnectionsToken.IsCancellationRequested) break;
if (!listener.Active)
{
continue;
}
if (listener.Pending())
{
try
{
TcpClient connection = await listener.AcceptTcpClientAsync();
//TODO: need to send it synchronised, since this causes a Cross-Thread when using WinForms
OnPendingConnection?.Invoke(this, connection);
}
catch (ObjectDisposedException x)
{
Write.Error(x.ToString());
}
}
}
}
}));
}
Я знаю, что могу использовать текстовое поле .InvokeRequired
и .Invoke
в графическом интерфейсе, но у меня такое чувство, чтосервер должен генерировать событие так, чтобы графический интерфейс не вызывал исключение Cross-Thread.
Есть ли способ вызвать обработчик событий в этой "бесконечной задаче", не вызывая этого исключения?