C# Ui freezes when calling a method

2019-09-16 11:04发布

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.

2条回答
我想做一个坏孩纸
2楼-- · 2019-09-16 11:36

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.

查看更多
再贱就再见
3楼-- · 2019-09-16 11:46

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

查看更多
登录 后发表回答