Steps.cs
1 //
2 // Copyright (c) Microsoft. All rights reserved.
3 // Licensed under the MIT license.
4 //
5 // Microsoft Bot Framework: http://botframework.com
6 //
7 // Bot Builder SDK GitHub:
8 // https://github.com/Microsoft/BotBuilder
9 //
10 // Copyright (c) Microsoft Corporation
11 // All rights reserved.
12 //
13 // MIT License:
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
21 //
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 //
25 // THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 //
33 
34 using System;
35 using System.Collections.Generic;
36 using System.Diagnostics;
37 using System.Linq;
38 using System.Threading.Tasks;
39 
41 
42 namespace Microsoft.Bot.Builder.FormFlow.Advanced
43 {
44  internal class FieldStep<T> : IStep<T>
45  where T : class
46  {
47  public FieldStep(string name, IForm<T> form)
48  {
49  _name = name;
50  _field = form.Fields.Field(name);
51  }
52 
53  public string Name
54  {
55  get
56  {
57  return _name;
58  }
59  }
60 
61  public StepType Type
62  {
63  get
64  {
65  return StepType.Field;
66  }
67  }
68 
69  public TemplateBaseAttribute Annotation
70  {
71  get
72  {
73  return _field.Prompt?.Annotation;
74  }
75  }
76 
77  public IField<T> Field
78  {
79  get
80  {
81  return _field;
82  }
83  }
84 
85  public void SaveResources()
86  {
87  _field.SaveResources();
88  }
89 
90  public void Localize()
91  {
92  _field.Localize();
93  }
94 
95  public bool Active(T state)
96  {
97  return _field.Active(state);
98  }
99 
100  public async Task<bool> DefineAsync(T state)
101  {
102  return await _field.DefineAsync(state);
103  }
104 
105  public FormPrompt Start(IDialogContext context, T state, FormState form)
106  {
107  form.SetPhase(StepPhase.Responding);
108  form.StepState = new FieldStepState(FieldStepStates.SentPrompt);
109  return _field.Prompt.Prompt(state, _field, _field.Prompt.Recognizer.PromptArgs());
110  }
111 
112  public IEnumerable<TermMatch> Match(IDialogContext context, T state, FormState form, string input)
113  {
114  IEnumerable<TermMatch> matches = null;
115  Debug.Assert(form.Phase() == StepPhase.Responding);
116  var stepState = (FieldStepState)form.StepState;
117  if (stepState.State == FieldStepStates.SentPrompt)
118  {
119  matches = _field.Prompt.Recognizer.Matches(input, _field.GetValue(state));
120  }
121  else if (stepState.State == FieldStepStates.SentClarify)
122  {
123  var fieldState = (FieldStepState)form.StepState;
124  var iprompt = _field.Prompt;
125  var choiceRecognizer = ClarifyRecognizer(fieldState, iprompt.Recognizer);
126  matches = MatchAnalyzer.Coalesce(MatchAnalyzer.HighestConfidence(choiceRecognizer.Matches(input)), input).ToArray();
127  if (matches.Count() > 1)
128  {
129  matches = new TermMatch[0];
130  }
131  }
132 #if DEBUG
133  if (FormDialog.DebugRecognizers)
134  {
135  MatchAnalyzer.PrintMatches(matches, 2);
136  }
137 #endif
138  return matches;
139  }
140 
141  public async Task<StepResult> ProcessAsync(IDialogContext context, T state, FormState form, string input, IEnumerable<TermMatch> matches)
142  {
143  ValidateResult feedback = new ValidateResult();
144  feedback.IsValid = true;
145  feedback.Feedback = null;
146  feedback.FeedbackCard = null;
147  feedback.Choices = null;
148  FormPrompt prompt = null;
149  FormPrompt feedbackPrompt = null;
150  var iprompt = _field.Prompt;
151  var fieldState = (FieldStepState)form.StepState;
152  object response = null;
153  if (fieldState.State == FieldStepStates.SentPrompt)
154  {
155  // Response to prompt
156  var firstMatch = matches.FirstOrDefault();
157  if (matches.Count() == 1)
158  {
159  response = firstMatch.Value;
160  if (_field.AllowsMultiple && response != null
161  && (response.GetType() == typeof(string) || !response.GetType().IsIEnumerable()))
162  {
163  response = new List<object>() { response };
164  }
165  feedback = await SetValueAsync(state, response, form);
166  if (!feedback.IsValid && feedback.Choices != null)
167  {
168  var choices = new Ambiguous(input.Substring(firstMatch.Start, firstMatch.Length), feedback.Choices);
169  fieldState.State = FieldStepStates.SentClarify;
170  fieldState.Settled = new List<object>();
171  fieldState.Clarifications = new List<Ambiguous>() { choices };
172  response = SetValue(state, null);
173  prompt = ClarifyPrompt((FieldStepState)form.StepState, iprompt.Recognizer, state);
174  }
175  }
176  else if (matches.Count() > 1)
177  {
178  // Check multiple matches for ambiguity
179  var groups = MatchAnalyzer.GroupedMatches(matches);
180  // 1) Could be multiple match groups like for ingredients.
181  // 2) Could be overlapping matches like "onion".
182  // 3) Could be multiple matches where only one is expected.
183 
184  if (!_field.AllowsMultiple)
185  {
186  // Create a single group of all possibilities if only want one value
187  var mergedGroup = groups.SelectMany((group) => group).ToList();
188  groups = new List<List<TermMatch>>() { mergedGroup };
189  }
190  var ambiguous = new List<Ambiguous>();
191  var settled = new List<object>();
192  foreach (var choices in groups)
193  {
194  if (choices.Count > 1)
195  {
196  var unclearResponses = string.Join(" ", (from choice in choices select input.Substring(choice.Start, choice.Length)).Distinct());
197  var values = from match in choices select match.Value;
198  ambiguous.Add(new Ambiguous(unclearResponses, values));
199  }
200  else
201  {
202  var matchValue = choices.First().Value;
203  if (matchValue != null && matchValue.GetType() != typeof(string) && matchValue.GetType().IsIEnumerable())
204  {
205  foreach (var value in (System.Collections.IEnumerable)matchValue)
206  {
207  settled.Add(value);
208  }
209  }
210  else
211  {
212  settled.Add(choices.First().Value);
213  }
214  }
215  }
216  if (settled.Count > 1)
217  {
218  // Remove no preference if present
219  settled.Remove(null);
220  }
221 
222  if (ambiguous.Count > 0)
223  {
224  // Need 1 or more clarifications
225  fieldState.State = FieldStepStates.SentClarify;
226  fieldState.Settled = settled;
227  fieldState.Clarifications = ambiguous;
228  response = SetValue(state, null);
229  prompt = ClarifyPrompt((FieldStepState)form.StepState, iprompt.Recognizer, state);
230  }
231  else
232  {
233  if (_field.AllowsMultiple)
234  {
235  response = settled;
236  feedback = await SetValueAsync(state, response, form);
237  }
238  else
239  {
240  Debug.Assert(settled.Count == 1);
241  response = settled.First();
242  feedback = await SetValueAsync(state, response, form);
243  }
244  }
245  }
246  var unmatched = MatchAnalyzer.Unmatched(input, matches);
247  var unmatchedWords = string.Join(" ", unmatched);
248  var nonNoise = Language.NonNoiseWords(Language.WordBreak(unmatchedWords)).ToArray();
249  fieldState.Unmatched = null;
250  if (_field.Prompt.Annotation.Feedback == FeedbackOptions.Always)
251  {
252  fieldState.Unmatched = string.Join(" ", nonNoise);
253  }
254  else if (_field.Prompt.Annotation.Feedback == FeedbackOptions.Auto
255  && nonNoise.Any()
256  && unmatched.Any())
257  {
258  fieldState.Unmatched = string.Join(" ", nonNoise);
259  }
260  }
261  else if (fieldState.State == FieldStepStates.SentClarify)
262  {
263  if (matches.Count() == 1)
264  {
265  // Clarified ambiguity
266  var clarify = NeedsClarification(fieldState);
267  fieldState.Settled.Add(matches.First().Value);
268  fieldState.Clarifications.Remove(clarify);
269  if (prompt == null)
270  {
271  // No clarification left, so set the field
272  if (_field.AllowsMultiple)
273  {
274  response = fieldState.Settled;
275  feedback = await SetValueAsync(state, response, form);
276  }
277  else
278  {
279  Debug.Assert(fieldState.Settled.Count == 1);
280  response = fieldState.Settled.First();
281  feedback = await SetValueAsync(state, response, form);
282  }
283  form.SetPhase(StepPhase.Completed);
284  }
285  }
286  }
287  if (form.Phase() == StepPhase.Completed)
288  {
289  form.StepState = null;
290  if (fieldState.Unmatched != null)
291  {
292  if (feedback.FeedbackCard != null)
293  {
294  feedbackPrompt = feedback.FeedbackCard;
295  }
296  else if (feedback.Feedback != null)
297  {
298  feedbackPrompt = new FormPrompt { Prompt = feedback.Feedback };
299  }
300  else
301  {
302  if (fieldState.Unmatched != "")
303  {
304  feedbackPrompt = new Prompter<T>(_field.Template(TemplateUsage.Feedback), _field.Form, null).Prompt(state, _field, fieldState.Unmatched);
305  }
306  else
307  {
308  feedbackPrompt = new Prompter<T>(_field.Template(TemplateUsage.Feedback), _field.Form, null).Prompt(state, _field);
309  }
310  }
311  }
312  }
313  var next = _field.Next(response, state);
314  return new StepResult(feedback.IsValid, next, feedbackPrompt ?? (feedback.FeedbackCard ?? new FormPrompt { Prompt = feedback.Feedback }), prompt);
315  }
316 
317  public bool InClarify(FormState form)
318  {
319  var state = (FieldStepState)form.StepState;
320  return state.State == FieldStepStates.SentClarify;
321  }
322 
323  public FormPrompt NotUnderstood(IDialogContext context, T state, FormState form, string input)
324  {
325  FormPrompt feedback = null;
326  var iprompt = _field.Prompt;
327  var fieldState = (FieldStepState)form.StepState;
328  if (fieldState.State == FieldStepStates.SentPrompt)
329  {
330  feedback = Template(TemplateUsage.NotUnderstood).Prompt(state, _field, input);
331  }
332  else if (fieldState.State == FieldStepStates.SentClarify)
333  {
334  feedback = Template(TemplateUsage.NotUnderstood, ClarifyRecognizer(fieldState, _field.Prompt.Recognizer)).Prompt(state, _field, input);
335  }
336  return feedback;
337  }
338 
339  public bool Back(IDialogContext context, T state, FormState form)
340  {
341  bool backedUp = false;
342  var fieldState = (FieldStepState)form.StepState;
343  if (fieldState.State == FieldStepStates.SentClarify)
344  {
345  var desc = _field.Form.Fields.Field(_name);
346  if (desc.AllowsMultiple)
347  {
348  desc.SetValue(state, fieldState.Settled);
349  }
350  else if (fieldState.Settled.Any())
351  {
352  desc.SetValue(state, fieldState.Settled.First());
353  }
354  form.SetPhase(StepPhase.Ready);
355  backedUp = true;
356  }
357  return backedUp;
358  }
359 
360  public FormPrompt Help(T state, FormState form, string commandHelp)
361  {
362  var fieldState = (FieldStepState)form.StepState;
363  IPrompt<T> template;
364  if (fieldState.State == FieldStepStates.SentClarify)
365  {
366  template = Template(TemplateUsage.HelpClarify, ClarifyRecognizer(fieldState, _field.Prompt.Recognizer));
367  }
368  else
369  {
370  template = Template(TemplateUsage.Help, _field.Prompt.Recognizer);
371  }
372  var help = template.Prompt(state, _field, "* " + template.Recognizer.Help(state, _field.GetValue(state)), commandHelp);
373  return new FormPrompt { Prompt = "* " + help.Prompt, Buttons = help.Buttons };
374  }
375 
376  public IEnumerable<string> Dependencies
377  {
378  get
379  {
380  return Array.Empty<string>();
381  }
382  }
383 
384  private IPrompt<T> Template(TemplateUsage usage, IRecognize<T> recognizer = null)
385  {
386  var template = _field.Template(usage);
387  return new Prompter<T>(template, _field.Form, recognizer == null ? _field.Prompt.Recognizer : recognizer);
388  }
389 
390  private object SetValue(T state, object value)
391  {
392  var desc = _field.Form.Fields.Field(_name);
393  if (value == null)
394  {
395  desc.SetUnknown(state);
396  }
397  else
398  {
399  desc.SetValue(state, value);
400  }
401  return value;
402  }
403 
404  private async Task<ValidateResult> SetValueAsync(T state, object value, FormState form)
405  {
406  var desc = _field.Form.Fields.Field(_name);
407  var feedback = await desc.ValidateAsync(state, value);
408  if (feedback.IsValid)
409  {
410  SetValue(state, feedback.Value);
411  form.SetPhase(StepPhase.Completed);
412  }
413  else if (feedback.Feedback == null)
414  {
415  feedback.Feedback = "";
416  }
417  return feedback;
418  }
419 
420  private Ambiguous NeedsClarification(FieldStepState stepState)
421  {
422  Ambiguous clarify = null;
423  foreach (var clarification in stepState.Clarifications)
424  {
425  if (clarification.Values.Length > 1)
426  {
427  clarify = clarification;
428  break;
429  }
430  }
431  return clarify;
432  }
433 
434  private class FieldClarify : Field<T>
435  {
436  public FieldClarify(IField<T> root)
437  : base(root.Name, FieldRole.Value)
438  {
439  Form = root.Form;
440  var template = root.Template(TemplateUsage.Clarify);
441  SetPrompt(new PromptAttribute(template));
442  ReplaceTemplate(template);
443  ReplaceTemplate(root.Template(template.AllowNumbers ? TemplateUsage.EnumOneNumberHelp : TemplateUsage.EnumManyNumberHelp));
444  }
445 
446  public override bool IsUnknown(T state)
447  {
448  return true;
449  }
450  }
451 
452  private IField<T> ClarifyField(Ambiguous clarify, IRecognize<T> recognizer)
453  {
454  var field = new FieldClarify(_field);
455  foreach (var value in clarify.Values)
456  {
457  var choice = value as Choice;
458  if (choice != null)
459  {
460  field.AddDescription(choice.Value,
461  choice.Description.Description,
462  choice.Description.Image,
463  choice.Description.Message);
464  field.AddTerms(choice.Value, choice.Terms.Alternatives);
465  }
466  else
467  {
468  var desc = recognizer.ValueDescription(value);
469  field.AddDescription(value, desc.Description, desc.Image);
470  field.AddTerms(value, recognizer.ValidInputs(value).ToArray());
471  }
472  }
473  return field;
474  }
475 
476  private IRecognize<T> ClarifyRecognizer(FieldStepState stepState, IRecognize<T> recognizer)
477  {
478  var clarify = NeedsClarification(stepState);
479  return (clarify != null ? new RecognizeEnumeration<T>(ClarifyField(clarify, recognizer)) : null);
480  }
481 
482  private FormPrompt ClarifyPrompt(FieldStepState stepState, IRecognize<T> recognizer, T state)
483  {
484  var clarify = NeedsClarification(stepState);
485  FormPrompt prompt = null;
486  if (clarify != null)
487  {
488  var field = ClarifyField(clarify, recognizer);
489  var prompter = new Prompter<T>(field.Template(TemplateUsage.Clarify), field.Form, new RecognizeEnumeration<T>(field));
490  prompt = prompter.Prompt(state, field, clarify.Response);
491  }
492  return prompt;
493  }
494 
495  internal enum FieldStepStates { Unknown, SentPrompt, SentClarify };
496 
497  [Serializable]
498  internal class Ambiguous
499  {
500  public readonly string Response;
501  public object[] Values;
502  public Ambiguous(string response, IEnumerable<object> values)
503  {
504  Response = response;
505  Values = values.ToArray<object>();
506  }
507  }
508 
509  [Serializable]
510  internal class FieldStepState
511  {
512  internal FieldStepStates State;
513  internal string Unmatched;
514  internal List<object> Settled;
515  internal List<Ambiguous> Clarifications;
516  public FieldStepState(FieldStepStates state)
517  {
518  State = state;
519  }
520  }
521 
522  private readonly string _name;
523  private readonly IField<T> _field;
524  }
525 
526  internal class ConfirmStep<T> : IStep<T>
527  where T : class
528  {
529  public ConfirmStep(IField<T> field)
530  {
531  _field = field;
532  }
533 
534  public bool Back(IDialogContext context, T state, FormState form)
535  {
536  return false;
537  }
538 
539  public IField<T> Field
540  {
541  get
542  {
543  return _field;
544  }
545  }
546 
547  public void SaveResources()
548  {
549  _field.SaveResources();
550  }
551 
552  public void Localize()
553  {
554  _field.Localize();
555  }
556 
557  public bool Active(T state)
558  {
559  return _field.Active(state);
560  }
561 
562  public IEnumerable<TermMatch> Match(IDialogContext context, T state, FormState form, string input)
563  {
564  return _field.Prompt.Recognizer.Matches(input);
565  }
566 
567  public string Name
568  {
569  get
570  {
571  return _field.Name;
572  }
573  }
574 
575  public TemplateBaseAttribute Annotation
576  {
577  get
578  {
579  return _field.Prompt?.Annotation;
580  }
581  }
582 
583  public FormPrompt NotUnderstood(IDialogContext context, T state, FormState form, string input)
584  {
585  var template = _field.Template(TemplateUsage.NotUnderstood);
586  var prompter = new Prompter<T>(template, _field.Form, null);
587  return prompter.Prompt(state, _field, input);
588  }
589 
590  public async Task<StepResult> ProcessAsync(IDialogContext context, T state, FormState form, string input, IEnumerable<TermMatch> matches)
591  {
592  var value = matches.First().Value;
593  form.StepState = null;
594  form.SetPhase((bool)value ? StepPhase.Completed : StepPhase.Ready);
595  var next = _field.Next(value, state);
596  return new StepResult(true, next, feedback: null, prompt: null);
597  }
598 
599  public async Task<bool> DefineAsync(T state)
600  {
601  return await _field.DefineAsync(state);
602  }
603 
604  public FormPrompt Start(IDialogContext context, T state, FormState form)
605  {
606  form.SetPhase(StepPhase.Responding);
607  return _field.Prompt.Prompt(state, _field);
608  }
609 
610  public FormPrompt Help(T state, FormState form, string commandHelp)
611  {
612  var template = _field.Template(TemplateUsage.HelpConfirm);
613  var prompt = new Prompter<T>(template, _field.Form, _field.Prompt.Recognizer);
614  var help = prompt.Prompt(state, _field, "* " + prompt.Recognizer.Help(state, null), commandHelp);
615  return new FormPrompt { Prompt = "* " + help.Prompt, Buttons = help.Buttons };
616  }
617 
618  public bool InClarify(FormState form)
619  {
620  return false;
621  }
622 
623  public StepType Type
624  {
625  get
626  {
627  return StepType.Confirm;
628  }
629  }
630 
631  public IEnumerable<string> Dependencies
632  {
633  get
634  {
635  return _field.Dependencies;
636  }
637  }
638 
639  private readonly IField<T> _field;
640  }
641 
642  internal class NavigationField<T> : Field<T>
643  where T : class
644  {
645  public NavigationField(string name, string startField, IForm<T> form, T state, FormState formState, Fields<T> fields)
646  : base(name, FieldRole.Value)
647  {
648  Form = form;
649  var field = form.Fields.Field(startField);
650  SetFieldDescription(_form.Configuration.Navigation);
651  SetOptional();
652  foreach (var value in formState.Next.Names)
653  {
654  var svalue = (string)value;
655  var sfield = form.Fields.Field(svalue);
656  var fieldPrompt = sfield.Template(TemplateUsage.NavigationFormat);
657  var prompter = new Prompter<T>(fieldPrompt, form, sfield.Prompt.Recognizer);
658  AddDescription(value, prompter.Prompt(state, sfield).Prompt, null, sfield.FieldDescription.Message ?? sfield.FieldDescription.Description);
659  AddTerms(value, form.Fields.Field(svalue).FieldTerms.ToArray());
660  }
661  var template = field.Template(TemplateUsage.Navigation);
662  SetPrompt(new PromptAttribute(template));
663  SetRecognizer(new RecognizeEnumeration<T>(this));
664  _prompt = new Prompter<T>(template, form, _recognizer, fields);
665  }
666 
667  public override bool IsUnknown(T state)
668  {
669  return true;
670  }
671  }
672 
673  internal class NavigationStep<T> : IStep<T>
674  where T : class
675  {
676  private const string _name = "__navigate__";
677  public NavigationStep(string startField, IForm<T> form, T state, FormState formState)
678  {
679  var fields = new Fields<T>();
680  _field = new NavigationField<T>(_name, startField, form, state, formState, fields);
681  fields.Add(_field);
682  _fields = fields;
683  }
684 
685  public bool Back(IDialogContext context, T state, FormState form)
686  {
687  form.Next = null;
688  return false;
689  }
690 
691  public IField<T> Field
692  {
693  get
694  {
695  return _field;
696  }
697  }
698 
699  public bool Active(T state)
700  {
701  return true;
702  }
703 
704  public IEnumerable<TermMatch> Match(IDialogContext context, T state, FormState form, string input)
705  {
706  return _field.Prompt.Recognizer.Matches(input);
707  }
708 
709  public string Name
710  {
711  get
712  {
713  return "Navigation";
714  }
715  }
716 
717  public TemplateBaseAttribute Annotation
718  {
719  get
720  {
721  return _field.Prompt.Annotation;
722  }
723  }
724 
725  public bool InClarify(FormState form)
726  {
727  return false;
728  }
729 
730  public FormPrompt NotUnderstood(IDialogContext context, T state, FormState form, string input)
731  {
732  var template = _field.Template(TemplateUsage.NotUnderstood);
733  return new Prompter<T>(template, _field.Form, _field.Prompt.Recognizer, _fields).Prompt(state, _field, input);
734  }
735 
736  public async Task<StepResult> ProcessAsync(IDialogContext context, T state, FormState form, string input, IEnumerable<TermMatch> matches)
737  {
738  NextStep next;
739  form.Next = null;
740  var val = matches.First().Value;
741  if (val == null)
742  {
743  next = new NextStep();
744  }
745  else
746  {
747  next = new NextStep(new string[] { (string)val });
748  }
749  return new StepResult(true, next, feedback: null, prompt: null);
750  }
751 
752  public Task<bool> DefineAsync(T state)
753  {
754  throw new NotImplementedException();
755  }
756 
757  public FormPrompt Start(IDialogContext context, T state, FormState form)
758  {
759  return _field.Prompt.Prompt(state, _field);
760  }
761 
762  public StepType Type
763  {
764  get
765  {
766  return StepType.Navigation;
767  }
768  }
769 
770  public FormPrompt Help(T state, FormState form, string commandHelp)
771  {
772  var recognizer = _field.Prompt.Recognizer;
773  var prompt = new Prompter<T>(_field.Template(TemplateUsage.HelpNavigation), _field.Form, recognizer, _fields);
774  var help = prompt.Prompt(state, _field, "* " + recognizer.Help(state, null), commandHelp);
775  return new FormPrompt { Prompt = "* " + help.Prompt, Buttons = help.Buttons };
776  }
777 
778  public void SaveResources()
779  {
780  }
781 
782  public void Localize()
783  {
784  }
785 
786  public IEnumerable<string> Dependencies
787  {
788  get
789  {
790  return Array.Empty<string>();
791  }
792  }
793 
794  private readonly IField<T> _field;
795  private readonly IFields<T> _fields;
796  }
797 
798  internal class MessageStep<T> : IStep<T>
799  where T : class
800  {
801  public MessageStep(MessageDelegate<T> generateMessage, ActiveDelegate<T> condition, IEnumerable<string> dependencies, IForm<T> form)
802  {
803  _name = "message" + form.Steps.Count.ToString();
804  _form = form;
805  _message = generateMessage;
806  _condition = (condition == null ? (state) => true : condition);
807  _dependencies = dependencies ?? form.Dependencies(form.Steps.Count);
808  }
809 
810  public MessageStep(PromptAttribute prompt, ActiveDelegate<T> condition, IEnumerable<string> dependencies, IForm<T> form)
811  {
812  _name = "message" + form.Steps.Count.ToString();
813  _form = form;
814  _promptDefinition = prompt;
815  _condition = (condition == null ? (state) => true : condition);
816  _dependencies = dependencies ?? form.Dependencies(form.Steps.Count);
817  }
818 
819  public bool Active(T state)
820  {
821  return _condition(state);
822  }
823 
824  public bool Back(IDialogContext context, T state, FormState form)
825  {
826  return false;
827  }
828 
829  public FormPrompt Help(T state, FormState form, string commandHelp)
830  {
831  return null;
832  }
833 
834  public IEnumerable<string> Dependencies
835  {
836  get
837  {
838  return _dependencies;
839  }
840  }
841 
842  public IField<T> Field
843  {
844  get
845  {
846  return null;
847  }
848  }
849 
850  public IEnumerable<TermMatch> Match(IDialogContext context, T state, FormState form, string input)
851  {
852  throw new NotImplementedException();
853  }
854 
855  public string Name
856  {
857  get
858  {
859  return _name;
860  }
861  }
862 
863  public TemplateBaseAttribute Annotation
864  {
865  get { return _promptDefinition; }
866  }
867 
868  public bool InClarify(FormState form)
869  {
870  return false;
871  }
872 
873  public FormPrompt NotUnderstood(IDialogContext context, T state, FormState form, string input)
874  {
875  throw new NotImplementedException();
876  }
877 
878  public Task<StepResult> ProcessAsync(IDialogContext context, T state, FormState form, string input, IEnumerable<TermMatch> matches)
879  {
880  throw new NotImplementedException();
881  }
882 
883  public async Task<bool> DefineAsync(T state)
884  {
885  if (_message != null)
886  {
887  _promptDefinition = await _message(state);
888  }
889  return true;
890  }
891 
892  public FormPrompt Start(IDialogContext context, T state, FormState form)
893  {
894  form.SetPhase(StepPhase.Completed);
895  var prompt = new Prompter<T>(_promptDefinition, _form, null);
896  return prompt.Prompt(state, null);
897  }
898 
899  public void SaveResources()
900  {
901  if (_message == null)
902  {
903  _form.Resources.Add(_name, _promptDefinition.Patterns);
904  }
905  }
906 
907  public void Localize()
908  {
909  if (_message == null)
910  {
911  string[] patterns;
912  _form.Resources.LookupValues(_name, out patterns);
913  if (patterns != null) _promptDefinition.Patterns = patterns;
914  }
915  }
916 
917  public StepType Type
918  {
919  get
920  {
921  return StepType.Message;
922  }
923  }
924 
925  private readonly string _name;
926  private readonly IForm<T> _form;
927  private PromptAttribute _promptDefinition;
928  private readonly MessageDelegate<T> _message;
929  private readonly ActiveDelegate<T> _condition;
930  private readonly IEnumerable<string> _dependencies;
931  }
932 }
FieldRole
The role the field plays in a form.
Definition: IField.cs:129
The context for the execution of a dialog&#39;s conversational process.
Match corresponds to a field, not a specific value in the field.
TemplateUsage
All of the built-in templates.
Definition: Attributes.cs:321
What to display when asked for help.
FeedbackOptions
Control how the user gets feedback after each entry.
Definition: Attributes.cs:261
Response when an input is not understood.
Field is used to get a value to set in the form state.
Core namespace for Dialogs and associated infrastructure.
Root namespace for the Microsoft Bot Builder SDK.