frameworksbotframeworkbotsformflow

microsoft bot framework typing indicator form flow(Form Builder)


I need to add typing indicator activity inside the form flow, I have used the following code but it only works out side of form flow, once the user enter the form builder the typing indicator does not appear.

 Activity replytyping1 = activity.CreateReply();
        replytyping1.Type = ActivityTypes.Typing;
        replytyping1.Text = null;
        ConnectorClient connector2 = new ConnectorClient(new Uri(activity.ServiceUrl));
        await connector2.Conversations.ReplyToActivityAsync(replytyping1);

I am using the following code inside dialog to call the form builder:

 var myform = new FormDialog<TrainingForm>(new TrainingForm(), TrainingForm.MYBuildForm, FormOptions.PromptInStart, null);
            context.Call<TrainingForm>(myform, AfterChildDialog);

my form builder code:

  public enum MoreHelp { Yes, No };
public enum Helpfull { Yes, No };

[Serializable]
public class TrainingForm
{

    public string More = string.Empty;
    public string usefull = string.Empty;
    [Prompt("Is there anything else I can help you with today? {||}")]
    [Template(TemplateUsage.NotUnderstood, "What does \"{0}\" mean?", ChoiceStyle = ChoiceStyleOptions.Auto)]
    public MoreHelp? needMoreHelp { get; set; }

    [Prompt("Was this helpful? {||}")]
    [Template(TemplateUsage.NotUnderstood, "What does \"{0}\" mean?", ChoiceStyle = ChoiceStyleOptions.Auto)]
    public Helpfull? WasHelpful { get; set; }

    public static IForm<TrainingForm> MYBuildForm()
    {

        return new FormBuilder<TrainingForm>()
            .Field(new FieldReflector<TrainingForm>(nameof(needMoreHelp))
                        .SetActive(state => true)
                        .SetNext(SetNext2).SetIsNullable(false))

            .Field(new FieldReflector<TrainingForm>(nameof(WasHelpful))
                        .SetActive(state => state.More.Contains("No"))
                        .SetNext(SetNext).SetIsNullable(false)).OnCompletion(async (context, state) =>
                        {
                            if (state.usefull == "No")
                            {
                                await context.PostAsync("Sorry I could not help you");
                            }
                            else if (state.usefull == "Yes")
                            {
                                await context.PostAsync("Glad I could help");

                            }

                            if(state.More == "Yes")
                            {
                                await context.PostAsync("Ok! How can I help?");

                            }

                            context.Done<object>(new object());

                        })                 
                .Build();
        }

Solution

  • If you are attempting to send the typing activity from the dialog that loaded the FormFlow dialog, it will not work because the code in the parent dialog does not execute every time the FormFlow dialog is loaded.

    However, you can modify the MessagesController and inspect the dialog stack. If the FormFlow dialog is the last dialog on the stack, then send typing:

        public async Task<HttpResponseMessage> Post([FromBody]Activity activity) {
            if (activity.Type == ActivityTypes.Message)
            {
                using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, activity))
                {
                    var botData = scope.Resolve<IBotData>();
                    await botData.LoadAsync(default(CancellationToken));
    
                    var stack = scope.Resolve<IDialogTask>();                    
                    if (stack.Frames != null && stack.Frames.Count > 0)
                    {
                        var lastFrame = stack.Frames[stack.Frames.Count - 1];
                        var frameValue = lastFrame.Target.GetType().GetFields()[0].GetValue(lastFrame.Target);
                        if(frameValue is FormDialog<TrainingForm>)
                        {
                            var typingReply = activity.CreateReply();
                            typingReply.Type = ActivityTypes.Typing;
    
                            var connector = new ConnectorClient(new Uri(activity.ServiceUrl));
                            await connector.Conversations.ReplyToActivityAsync(typingReply);            
    
                        }
                    }
                }
    
                await Conversation.SendAsync(activity, () => FormDialog.FromForm(TrainingForm.MYBuildForm));
            }
            else
            {
                this.HandleSystemMessage(activity);
            }
    
            return Request.CreateResponse(HttpStatusCode.OK); 
    }