Resolved Temporarily Pause Execution

in_valparaiso

Member
Joined
Apr 5, 2019
Messages
13
Programming Experience
10+
I am writing a type of AI chatbot for our organization which allows users to "chat" with the program and ask for help with "I forgot my password", "I lost my J drive" …

Everything works well, but too well. The minute the user asks the question, the response is immediately presented to the user and it seems unnatural. So I added a label that says "Typing ..." and hid it. When it comes time to present the response, I want to make the label visible, wait a period of time, hide the label and move on.

Here's an outline of what the software does

User types question and the input is placed in a richtextbox.
Appropriate response found.
** Show typing **
Add response to richtextbox
** Stop showing typing **
If there were additional comments
** Show typing **
Add additional comments
** Stop showing typing **
...

My logic for ** Show typing ** is:
public static void Typing(string text, Label lbl)
{
lbl.Visible = true;
Thread.Sleep((text.Length / 3) * 1000); // Average person types 3 characters a second. In doing this I can pause the average length of
// time to type the text being shown.
lbl.Visible = false;
}

=====
My issue is: with the code above, when the user types their input it pauses for whatever thread.sleep is set for (even though the method isn't even called at this point. Then after it pauses where it shouldn't, it never pauses again, so the computer response shows up immediately after the first pause. I never see the label made visible. What am I doing wrong? I probably did a horrible job explaining this.
 
If the thread sleeps then it's because you are calling Thread.Sleep. It won't randomly execute code that you didn't call. The issue is likely that that call is made before the UI thread can actually repaint the screen, so you never actually see the Label you made visible. Instead of Thread.Sleep, which should pretty much NEVER be called on the UI thread, try calling Task.Delay. That should wait at that point for the specified time before continuing without preventing things like the UI being repainted.
 
I should point out that you will need to await that call, so you will need to declare the method that calls it async:
C#:
public static async Task Typing(string text, Label lbl)
{
    lbl.Visible = true;
    await Task.Delay((text.Length / 3) * 1000); // Average person types 3 characters a second. In doing this I can pause the average length of
    // time to type the text being shown.
    lbl.Visible = false;
}
 
Also, it would make more sense to use text.Length * 333 rather than (text.Length / 3) * 1000. That's because an int divided by an int will always produce an int and discard the remainder, so 2/3 will produce 0, 11/3 will produce 3, etc.
 
Thanks jmcilhinney. I tried what you suggested but when I use your suggestion, I do not even get a pause. Below is my actual code. Perhaps quickly you can see where I am screwing up. Otherwise, I'll just table this part. FYI, the "name" of the computer is Barrington. I placed two
rows of slashes in the left margin to easily show you where I call the routine.

C#:
public static void BarringtonTyping(string response, Label lbl)
{
    lbl.Visible = true;
    Task.Delay(500);
    lbl.Visible = false;
}

private void txtInput_KeyDown(object sender, KeyEventArgs e)
{
    if (e.KeyCode == Keys.Enter)
    {
        // Add the user's input into the transcript.
        Transcript.Update(Globals.User.firstName, txtInput.Text, rtbTranscript,false);

        // Parse the input to find the appropriate response.
        int id = AI.ParseQuestionForID(txtInput.Text);

        // Now that we have found the appropriate response, run it.
        string response = AI.DoResponse(id);

        // Let's make sure we got a response
        if (!String.IsNullOrEmpty(Barrington.Text.ExtractStringFromTag(response, "response")))
        {
            // If this response completes the task, clear the dialogTopic global
            if (!String.IsNullOrEmpty(Barrington.Text.ExtractStringFromTag(response, "complete").Trim()))
            {
                Globals.Barrington.dialogTopic = "";
            }

            // Set a topic if this conversation is going to continue
            if (!String.IsNullOrEmpty(Barrington.Text.ExtractStringFromTag(response, "topic").Trim()))
            {
                Globals.Barrington.dialogTopic = Barrington.Text.ExtractStringFromTag(response, "topic").Trim();
            }

            // Display the response from Barrington
            bool _answer = false;
            if (!String.IsNullOrEmpty(Barrington.Text.ExtractStringFromTag(response, "answer").Trim()))
            {
                if (Barrington.Text.ExtractStringFromTag(response, "answer").Trim().ToLower() == "true")
                {
                    _answer = true;

                    // Clear the conversation topic
                    Globals.Barrington.dialogTopic = "";
                }
            }
            ///////
            ///////
            BarringtonTyping(response, lblBarringtonTyping);
            Transcript.Update("", Barrington.Text.ExtractStringFromTag(response, "response"), rtbTranscript, _answer);

            // Display any additional comments
            if (!String.IsNullOrEmpty(Barrington.Text.ExtractStringFromTag(response, "additionalComment").Trim()))
            {
                string[] _additional = Barrington.Text.ExtractStringFromTag(response, "additionalComment").Split('|');
                foreach (string addcomment in _additional)
                {
                    //
                    Transcript.Update("", addcomment, rtbTranscript);
                }
            }

            // If this is not an ongoing conversation, ask if Barrington can do anything
            // else
            if (String.IsNullOrEmpty(Globals.Barrington.dialogTopic))
            {
                if (Barrington.Text.ExtractStringFromTag(response, "suppress").Trim().ToLower() != "true")
                {
                    response = AI.Remarks("Closing");
                    //
                    Transcript.Update("", response, rtbTranscript);
                }
            }
        }

        txtInput.Clear();
        e.SuppressKeyPress = true;
        rtbTranscript.Select(rtbTranscript.Text.Length, 0);
        rtbTranscript.ScrollToCaret();
    }
}
 
Last edited by a moderator:
Thank you SO MUCH. That worked perfectly and I learned a lot. You rock! I'm new to this site. Is there a way to mark this as answered or give you kudos?
 
If you edit the first post in the thread, you can set the Prefix to Answered or Resolved. While it's not a hard and fast rule, I would suggest using Answered if you just requested information and Resolved if you wanted help to fix an issue with your code. Also, please set the Prefix to Question whenever posting new questions.

You can also Like someone else's post if you find it helpful.
 
Quick question: the reason behind doing this was so that a label would appear saying "Typing", pause for a moment, and then hide the label. Taking it to the next level, I have a wav file that sounds like someone typing. Is there a way I can get the wav to play during the Task.Delay?
 
Back
Top Bottom