1

I got a function called Connect() this function takes about 2-3seconds because it use some api requests. Now I want to find a way that my Ui dont freeze while ill start this function.

    private void connectToolStripMenuItem_Click(object sender, EventArgs e)
    {
        Connect() // << this tooks a lot of time
    }

I have tried to solve it with a thread

    private void connectToolStripMenuItem_Click(object sender, EventArgs e)
    {
        new Thread(Connect).Start();
    }

and a backgroudnworker

    private void backgroundWorkerConnect_DoWork(object sender, DoWorkEventArgs e)
    {
        Connect();
    }

but the programm still freezes.

   private void Connect()
    {
        if (InvokeRequired)
        {
            Invoke(new MethodInvoker(Connect));
        }
        else
        {
            if (!connected)
            {
                connected = true;
                verbindenToolStripMenuItem.Enabled = false;
                trennenToolStripMenuItem.Enabled = true;
                InfoStripStatus.Text = "Status: Connected";

                irc.joinRoom(channel, BotConnectingMessage);
                chatThread = new Thread(getMessage);
                chatThread.Start();
                loadLoyalty();
                updateTimer = new System.Threading.Timer(timerViewer, null, 0, 60000);
            }
        }
    }

Maybe I'm just doing something wrong and hope someone can help me.

8
  • Starting a new thread is not supposed to freeze UI because it has its own thread Commented Jul 29, 2017 at 14:07
  • And the Connect(); method doesn't rely or invoke anything on the UI-thread? If you replace whatever is in Connect() with System.Threading.Thread.Sleep(3000); does it still freeze the UI? (test it with the last two options) Commented Jul 29, 2017 at 14:08
  • Okay ill tryed it to replace the Connect() content with the sleep(3000) and there is now no more freeze. But i dont get it why because in the Connect() funktion is nothing who takes that long. Ill add the content of Connect() in the top :) Commented Jul 29, 2017 at 14:26
  • okay can u maybe give me an example of that... PLEEAAASSEEE :D Commented Jul 29, 2017 at 14:33
  • Here is a nice sample about how to use a background worker and how to keep your UI responsive while a long action is being performed. msdn.microsoft.com/fr-fr/library/cc221403(v=vs.95).aspx If you need to update UI controls from the background thread you should update the controls using their "Invoke" method. Commented Jul 29, 2017 at 14:37

2 Answers 2

2

Using another thread (whether via BackgroundWorker or by creating one directly) to call a method that does nothing more than to invoke some code back on the UI thread and then wait for it, is going to solve nothing. The code you care about is still executing in the UI thread, blocking it.

You should use async/await with Task.Run() to handle your work:

private async void connectToolStripMenuItem_Click(object sender, EventArgs e)
{
    await Connect();
}

private async Task Connect()
{
    if (!connected)
    {
        connected = true;
        verbindenToolStripMenuItem.Enabled = false;
        trennenToolStripMenuItem.Enabled = true;
        InfoStripStatus.Text = "Status: Connected";

        await Task.Run(() => irc.joinRoom(channel, BotConnectingMessage));
        chatThread = new Thread(getMessage);
        chatThread.Start();
        loadLoyalty();
        updateTimer = new System.Threading.Timer(timerViewer, null, 0, 60000);
    }
}

Depending on how slow loadLoyalty() is, you might also want await Task.Run(loadLoyalty); instead of just calling it directly.

The above will execute all of the code in the UI thread where it belongs, except the code you invoke via Task.Run().

There are other ways that the code could be refactored, including an alternative that works with BackgroundWorker (i.e. just using Control.Invoke() to do the first four statements, and run the rest in the Connect() method directly). But IMHO the above using async/await is the best option today.

Sign up to request clarification or add additional context in comments.

1 Comment

Thx mate after a bit of reading about asyn/await and Task it works with just a few changes
0

Okay that looks interessting. I will try to transfer it to the other functions because I found out that it is the updateTimer which freeze it.

    private void timerViewer(object state)
    {
        irc.sendChatMessage("/mods");
        UpdateStream();
        UpdateChatters();
    } 

    private void UpdateStream()
    {
        if (InvokeRequired)
        {
            Invoke(new MethodInvoker(UpdateStream));
        }
        else
        {
            StreamInformations = TwitchROClient.getStream(TwitchROClient.getIDbyUsername("xzaliax"));

            if (StreamInformations.stream != null)
            {

                viewers = StreamInformations.stream.Viewers;
                totalviews = StreamInformations.stream.channel.Views;

                if (followers == 0)
                {
                    followers = StreamInformations.stream.channel.Followers;
                }
                else
                {
                    if (followers < StreamInformations.stream.channel.Followers)
                    {
                        newFollower();
                    }
                    followers = StreamInformations.stream.channel.Followers;
                }


                InfoStripViewer.Text = "|  " + string.Format(CultureInfo.InvariantCulture, "{0:N0}", viewers).Replace(',', '.') + " :Viewer";
                InfoStripFollower.Text = "|  " + string.Format(CultureInfo.InvariantCulture, "{0:N0}", followers).Replace(',', '.') + " :Follower ";
                InfoStripTotalViewer.Text = "|  " + string.Format(CultureInfo.InvariantCulture, "{0:N0}", totalviews).Replace(',', '.') + " :Total Viewers";
                InfoStripStream.Text = "|  Stream: Online";
            }
            else
            {
                InfoStripViewer.Text = "|  -- :Viewer";
                InfoStripFollower.Text = "|  -- :Follower";
                InfoStripTotalViewer.Text = "|  -- :Total Viewers";
                InfoStripStream.Text = "|  Stream: Offline";
            }
        }
    }
    private void UpdateChatters()
    {
        if (InvokeRequired)
        {
            Invoke(new MethodInvoker(UpdateChatters));
        }
        else
        {
            ChannenlChatters = TwitchROClient.getChatters(channel);
            lbViewer.Items.Clear();

            if (ChannenlChatters != null)
            {
                if (ChannenlChatters.AllChatters != null)
                {
                    tbChat.Text += "Checking the viewer list..." + Environment.NewLine;
                    if (ChannenlChatters.AllChatters.Admins.Count >= 0) lbViewer.Items.Add("_____________Admins_____________");
                    foreach (string admin in ChannenlChatters.AllChatters.Admins)
                    {
                        lbViewer.Items.Add(String.Format("{0,5}", admin));
                    }
                    if (ChannenlChatters.AllChatters.Admins.Count >= 0) lbViewer.Items.Add("");

                    if (ChannenlChatters.AllChatters.Staff.Count >= 0) lbViewer.Items.Add("_____________Stuff______________");
                    foreach (string stuff in ChannenlChatters.AllChatters.Staff)
                    {
                        lbViewer.Items.Add(String.Format("{0,5}", stuff));
                    }
                    if (ChannenlChatters.AllChatters.Staff.Count >= 0) lbViewer.Items.Add("");

                    if (ChannenlChatters.AllChatters.GlobalMods.Count >= 0) lbViewer.Items.Add("___________Global Mods__________");
                    foreach (string globalmods in ChannenlChatters.AllChatters.GlobalMods)
                    {
                        lbViewer.Items.Add(String.Format("{0,5}", globalmods));
                    }

                    if (ChannenlChatters.AllChatters.GlobalMods.Count >= 0) lbViewer.Items.Add("");
                    foreach (string globalMods in ChannenlChatters.AllChatters.GlobalMods)
                    {
                        lbViewer.Items.Add(String.Format("{0,5}", globalMods));
                    }

                    if (ChannenlChatters.AllChatters.Moderators.Count >= 0) lbViewer.Items.Add("___________Moderators___________");
                    foreach (string moderator in ChannenlChatters.AllChatters.Moderators)
                    {
                        lbViewer.Items.Add(String.Format("{0,5}", moderator));
                    }

                    if (ChannenlChatters.AllChatters.Viewers.Count >= 0) lbViewer.Items.Add("____________Viewers_____________");
                    foreach (string viewers in ChannenlChatters.AllChatters.Viewers)
                    {
                        lbViewer.Items.Add(String.Format("{0,5}", viewers));
                    }
                }
            }
        }
    }

so i will read more about ascny and await and test it a bit

1 Comment

Your timer callback does the same thing your click handler did. It runs everything on the UI thread. Naturally, this blocks the UI thread while it's working. Without a good minimal reproducible example that reliably reproduces the problem, it's not possible to give any specific advice, but the basic solution is still the same: don't block the UI thread for long-running operations. You seem to be doing I/O so there may already be async methods you can call. If not, you can fallback on the await Task.Run() idiom, as in my answer posted here.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.