#c# #winforms
Вопрос:
Я хотел бы изменить текст текстового поля в моем Backgroundworker, но это не работает, и я не могу найти ошибку в своем коде.
Фоновый работник:
class Check_Server
{
WebSocket webSocket = new WebSocket("ws://localhost:8548");
private Form1 Form1;
public void Check_WebSocket(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
while (!worker.CancellationPending)
{
Console.WriteLine("checking connection");
if (webSocket.IsAlive == true)
{
Console.WriteLine("connected");
}
else
{
Console.WriteLine("not connected");
Form1 form = new Form1();
form.SetText("XYZ");
MakeNewConnection();
}
}
}
void MakeNewConnection()
{
webSocket.Connect();
Thread.Sleep(10000);
}
}
Форма:
public void SetText(string text)
{
if (InvokeRequired)
{
this.Invoke((MethodInvoker)delegate () { SetText(text); });
return;
}
textBox1.Text = text;
}
Комментарии:
1. Это
textBox1.Text =…
соответствует действительности?2. Проблема в том, что вы создаете экземпляр Form1 в фоновом потоке вашего BackgroundWorker (и не показываете форму).
3. @Steeeve Как я могу это исправить? если я использую
private Form1 Form1;
, я получаю, что форма 1 была нулевой4. Вы объявляете Form1 как поле класса, но никогда не присваиваете этой переменной новый экземпляр. Вместо этого вы создаете новый экземпляр в рабочей процедуре BackgroundWorker и назначаете его локальной переменной. Чтобы исправить это, мы должны больше знать о вашей цели.
Ответ №1:
Websockets в winforms стало намного проще с помощью библиотеки от Мариуша Котаса, которая, возможно, неудивительно, называется Websocket.Клиент ; если вы откроете менеджер пакетов VS’ nuget и выполните поиск в нем, вы найдете его (в настоящее время около версии 4.3).
Настройка может выглядеть так:
private WebsocketClient _cws;
private async void ConnectButton_Click(..){
_cws = new WebsocketClient(new Uri("your uri here"));
_cws.MessageReceived.Subscribe(msg => MessageReceived(msg.Text));
_cws.DisconnectionHappened.Subscribe(info => DoSomething("Disconnection happened: " info));
}
Отправка сообщения может выглядеть так:
private async void ConnectButton_Click(..){
_cws.Send(messageTextBox.Text);
}
Получение сообщения подписано выше:
private void MessageReceived(string msg)
//local function for logging
void addAndScrollAsync()
{
_messagesListBox.Items.Add( msg);
//this scrolls to show new messages while the listbox is at the bottom, but doesn't if it's been scrolled up
int visibleItems = _messagesListBox.ClientSize.Height / _messagesListBox.ItemHeight;
if (_messagesListBox.Items.Count > visibleItems amp;amp; _messagesListBox.TopIndex > _messagesListBox.Items.Count - visibleItems - 2)
_messagesListBox.TopIndex = _messagesListBox.Items.Count - visibleItems 1;
}
_messagesListBox.InvokeEx(() => addAndScrollAsync());
}
У меня есть несколько вспомогательных расширений для любого вызова:
public static class ControlExtensions
{
public static TResult InvokeEx<TControl, TResult>(this TControl control,
Func<TControl, TResult> func)
where TControl : Control
{
return control.InvokeRequired
? (TResult)control.Invoke(func, control)
: func(control);
}
public static void InvokeEx<TControl>(this TControl control,
Action<TControl> func)
where TControl : Control
{
control.InvokeEx(c => { func(c); return c; });
}
public static void InvokeEx<TControl>(this TControl control, Action action)
where TControl : Control
{
control.InvokeEx(c => action());
}
}
Комментарии:
1. У вас есть какие-либо идеи, как я могу выполнить цикл с этим пакетом, который проверяет, подключен ли сокет к сети, или я могу получить статус с его помощью?
2. Я не думаю, что вам нужно беспокоиться об этом; после подключения он остается подключенным (и снова подключается, если происходит отключение), пока вы его не отключите. Я думаю, что на домашней странице проекта есть какая-то информация .. Посмотрите здесь и посмотрите, есть ли какой-нибудь более глубокий пример: github.com/Marfusios/websocket-client ?
3. (У него есть свойство isRunning, которое сообщит вам, подключен ли он.. Я никогда им не пользовался)
4. Хорошо, спасибо, этот пакет намного лучше
Ответ №2:
Вы не показываете свою форму. Добавьте form.Show()
или form.ShowDialog()
, в зависимости от того, хотите ли вы подождать, пока пользователь закроет форму.
Кроме того, я нашел этот метод расширения весьма полезным для внесения потокобезопасных изменений в элемент управления. Используйте его так: textBox1.InvokeSave(() => textBox1.Text = text);
.
public static partial class ControlExtensions
{
public static void InvokeSave(this Control control, Action action)
{
Delegate del = action;
try
{
if (control.InvokeRequired)
{
control.Invoke(del);
}
else action();
}
catch (ObjectDisposedException)
{
// guess do nothing is fine then
}
}
}
Комментарии:
1. Теперь я вижу, что моя форма всегда перезагружается, но текстовое поле не меняется