Search code examples
c#multithreadingtaskinvokemqttnet

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 += 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.


Solution

  • 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.