Microsoft Bot Framework中的FormBuilder自定义字段

使用AlarmBot示例和改进的三明治机器人 ,我试图了解如何将FormBuilder与自定义对话框行为结合起来。 具体来说,我想采用Alarm Bot SetAlarm方法

SetAlarm(IDialogContext context, LuisResult result) 

并在SandwichBot中使用相同的Chronic.Parser作为DeliveryTime字段。 怎么做? 我看过实施IField,但我不确定它会是什么样子。

在查看并单步执行源代码之后,最简单的答案与IFieldState无关。 关键接口是IRecognize。 正确使用它需要了解一些正在进行的内容。

首先创建自己的自定义字段。 该框架很好地允许我们从FieldReflector派生,它完成大部分工作。

 public class BetterDateTimeField : FieldReflector { public BetterDateTimeField(string name, bool ignoreAnnotations = false) : base(name, ignoreAnnotations) { } public override IForm Form { set { base.Form = value; base.SetRecognizer(new BetterDateTimeRecognizer(this, CultureInfo.CurrentCulture)); } } } 

这里的主要思想是创建自己的识别器,因为这是获取原始输入文本的部分。 诀窍是知道何时可以创建识别器的实例。 必须在字段表格设置完成完成。 底层的Recognizer基类将查看构造函数中的fields表单。 (如果您完全放弃使用基本识别器类,这可能不是问题。)

接下来,您可以创建自己的自定义IRecognize实现。 不幸的是,僵尸框架密封了许多基本/原始类型的识别器类,因此从RecognizeDateTime派生并且重载Parse不是一个选项(希望有一天他们会解封它们)。 但是,复制和编辑到您自己的自定义类很容易。

 using Chronic; public class BetterDateTimeRecognizer : RecognizePrimitive where T : class { private CultureInfo _culture; private Parser _parser; public BetterDateTimeRecognizer(IField field, CultureInfo culture) : base(field) { _culture = culture; _parser = new Chronic.Parser(); } public override string Help(T state, object defaultValue) { var prompt = new Prompter(_field.Template(TemplateUsage.DateTimeHelp), _field.Form, null); var args = HelpArgs(state, defaultValue); return prompt.Prompt(state, _field.Name, args.ToArray()); } public override TermMatch Parse(string input) { TermMatch match = null; // the original code //DateTime dt; //if (DateTime.TryParse(input, out dt)) //{ // match = new TermMatch(0, input.Length, 1.0, dt); //} var parse = _parser.Parse(input); if (parse != null && parse.Start.HasValue) { match = new TermMatch(0, input.Length, 1.0, parse.Start.Value); } return match; } public override IEnumerable ValidInputs(object value) { yield return ValueDescription(value); } public override string ValueDescription(object value) { return ((DateTime)value).ToString(CultureInfo.CurrentCulture.DateTimeFormat); } } 

最后,您只需将其连接到BuildForm()中的表单构建器:

 var form = builder.Message("Hello there. What can I help you today") .Field(new BetterDateTimeField("") .Build(); 

最初我们在FormFlow中使用Chronic for DateTime字段,但是当我们转移到签署我们的dll时,我们再也无法使用未签名的C#Chronic库。 我已经联系了作者但要求他签名,但还没有回复 – 如果他这样做,我们会把它作为FormFlow的一部分。

至于实现IField,如果您愿意,可以从Field派生并提供您自己的IFieldState实现。 Field具有所有声明性内容的数据结构,您可以覆盖所有方法。 这将允许您在未签名的DLL中使用Chronic。