英文:
Changing WindowsForms UI in a Task c#
问题
I wrote a windows forms application where I receive messages with MQTTNet from the broker. I want to change the UI according to the received message. But I couldn't make it happen. I took the client code from the MQTTNet github page. When I receive the message, I want to change a label. Because it is a task, I had to call the invoke function, but it never executes. The function to change the label is called, but the change statement is never reached.
public Form1()
{
InitializeComponent();
trainCount = 1;
tagCount = 2;
trains = new Train[trainCount];
tags = new Tag[tagCount];
InitializeTrains();
InitializeTags();
control = this;
Task task = Handle_Received_Application_Message();
}
public async Task Handle_Received_Application_Message()
{
var mqttFactory = new MqttFactory();
using (var mqttClient = mqttFactory.CreateMqttClient())
{
var mqttClientOptions = new MqttClientOptionsBuilder().WithTcpServer("127.0.0.1").Build();
mqttClient.ApplicationMessageReceivedAsync += async e =>
{
Console.WriteLine("Received application message.");
Console.WriteLine(e.ApplicationMessage.ConvertPayloadToString());
for (int i = 0; i < tagCount; i++)
{
if (tags[i].code.CompareTo(e.ApplicationMessage.ConvertPayloadToString()) == 0)
{
for (int k = 0; k < trainCount; k++)
{
if (e.ApplicationMessage.ConvertPayloadToString().Substring(0, 2).CompareTo(trains[k].code) == 0)
{
Console.WriteLine("In Tag Event");
trains[k].currentTag = tags[i];
var message = e.ApplicationMessage.ConvertPayloadToString();
await ChangeUI(); // Change UI is called here.
}
}
}
}
};
await mqttClient.ConnectAsync(mqttClientOptions, CancellationToken.None);
var mqttSubscribeOptions = mqttFactory.CreateSubscribeOptionsBuilder()
.WithTopicFilter(
f =>
{
f.WithTopic("anten/main");
})
.Build();
await mqttClient.SubscribeAsync(mqttSubscribeOptions, CancellationToken.None);
Console.WriteLine("MQTT client subscribed to topic.");
Console.ReadKey();
}
}
public async Task ChangeUI()
{
if (InvokeRequired)
BeginInvoke(new MethodInvoker(
delegate
{
ChangeUI().Wait();
}
));
else
{
label1.Text = "sadasdasd"; // Code never reaches here.
}
}
I tried creating a different thread when a message is received, but it didn't work neither.
Any help would be appreciated. I got stuck on this for 10 hours.
英文:
I wrote a windows forms application where I receive messages with MQTTNet from the broker. I want to change the UI according to the received message. But I couldn't make it happen. I took the client code from the MQTTNet github page. When I receive the message, I want to change a label. Because it is a task, I had to call the invoke function, but it never executes. The function to change the label is called, but the change statement is never reached.
public Form1()
{
InitializeComponent();
trainCount = 1;
tagCount = 2;
trains = new Train[trainCount];
tags = new Tag[tagCount];
InitializeTrains();
InitializeTags();
control = this;
Task task = Handle_Received_Application_Message();
}
public async Task Handle_Received_Application_Message()
{
var mqttFactory = new MqttFactory();
using (var mqttClient = mqttFactory.CreateMqttClient())
{
var mqttClientOptions = new MqttClientOptionsBuilder().WithTcpServer("127.0.0.1").Build();
mqttClient.ApplicationMessageReceivedAsync += e =>
{
Console.WriteLine("Received application message.");
Console.WriteLine(e.ApplicationMessage.ConvertPayloadToString());
for (int i = 0; i < tagCount; i++)
{
if (tags[i].code.CompareTo(e.ApplicationMessage.ConvertPayloadToString()) == 0)
{
for (int k = 0; k < trainCount; k++)
{
if (e.ApplicationMessage.ConvertPayloadToString().Substring(0, 2).CompareTo(trains[k].code) == 0)
{
Console.WriteLine("In Tag Event");
trains[k].currentTag = tags[i];
var message = e.ApplicationMessage.ConvertPayloadToString();
ChangeUI(); //Change UI is called here.
}
}
}
}
return Task.CompletedTask;
};
await mqttClient.ConnectAsync(mqttClientOptions, CancellationToken.None);
var mqttSubscribeOptions = mqttFactory.CreateSubscribeOptionsBuilder()
.WithTopicFilter(
f =>
{
f.WithTopic("anten/main");
})
.Build();
await mqttClient.SubscribeAsync(mqttSubscribeOptions, CancellationToken.None);
Console.WriteLine("MQTT client subscribed to topic.");
Console.ReadKey();
}
}
public void ChangeUI()
{
if (InvokeRequired)
BeginInvoke(new MethodInvoker(
delegate
{
ChangeUI();
}
));
else
{
label1.Text = "sadasdasd"; // Code never reaches here.
}
}
I tried creating a different thread when a message is received, but it didn't work neither.
Any help would be appreciated. I got stuck on this for 10 hours.
答案1
得分: 2
Console.ReadKey
会阻止 Windows 消息循环执行,从而阻止任何 UI 更新。
我建议移除 Console.ReadKey
,并且还要移除 Handle_Received_Application_Message
中的 using
,以便不销毁客户端。而是在 Handle_Received_Application_Message
中创建一个成员变量来持有客户端,在应用程序开始关闭时进行销毁。
英文:
Console.ReadKey
will prevent the Windows message loop from executing, which prevents any UI updates.
I recommend removing Console.ReadKey
and also removing the using
in Handle_Received_Application_Message
so the client is not disposed. Instead of disposing the client in Handle_Received_Application_Message
, create a member variable to hold the client and dispose it when your application begins to shut down.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论