예제 #1
0
        /// <summary>
        /// Get prompt waterfall steps for info collection
        /// </summary>
        /// <param name="info">property info</param>
        /// <returns>List of waterfall steps for property collection</returns>
        private IEnumerable <WaterfallStep> GetPromptWaterfallSteps()
        {
            var steps = new List <WaterfallStep>();

            // Add steps to get properties and set previous one
            PromptPropertyInfo previousProp = null;

            foreach (var prop in promptProperties)
            {
                steps.Add(this.BuildWaterfallStep(previousProp, prop));
                previousProp = prop;
            }

            // Add step to set last property
            steps.Add(this.BuildWaterfallStep(previousProp, null));

            return(steps);
        }
예제 #2
0
        /// <summary>
        /// Get a WaterfallStep given previous property and current property which need to be collected.
        /// The waterfall step will record previous property value and prompt for new property value when needed.
        /// NOTE - we need this function since we need eager evaluation of previousProp and currentProp.
        /// </summary>
        /// <param name="previousProp">previous property which has already been prompted. null means current prop is the first one</param>
        /// <param name="currentProp">current property which needs to be prompted. null means no more.</param>
        /// <returns>A waterstep delegate which does the real work</returns>
        private WaterfallStep BuildWaterfallStep(PromptPropertyInfo previousProp, PromptPropertyInfo currentProp)
        {
            return(async(WaterfallStepContext stepContext, CancellationToken cancellationToken) =>
            {
                var intentContext = stepContext.Options as TContext;

                // Try to save the value collected from previous step
                if (previousProp?.Setter != null)
                {
                    // We want the property to be nullable so that we can check whether it's set or not.
                    // However, we cannot convert stepContext.Result of type object with int value to int? using Convert.ChangeType.
                    // So we try to convert stepContext.Result to the underlying non nullable type first.
                    // The Setter will handle non-nullable to nullable conversion automatically.
                    var targetNonNullableType = Nullable.GetUnderlyingType(previousProp.PropertyType) ?? previousProp.PropertyType;
                    var convertedValue = Convert.ChangeType(stepContext.Result, targetNonNullableType);
                    previousProp.Setter(intentContext, convertedValue);
                }

                object currentPropertyValue = null;
                if (currentProp?.Getter != null)
                {
                    // Collect info for current property.
                    // We do null check to see whether the value has been set or not.
                    // This means that the corresponding IntentContext property needs to be "nullable".
                    currentPropertyValue = currentProp.Getter(intentContext);
                    if (currentPropertyValue == null)
                    {
                        // current property is not collected yet. Prompt and collect
                        return await stepContext.PromptAsync(currentProp.PromptDialog.Id, currentProp.PromptOptions, cancellationToken);
                    }
                }

                // If we reach here, it's either no new info needs to be collected (currentGetter == null),
                // or current property is already set (currentProperty != null).
                // Move to next step and pass the currentProperty value.
                return await stepContext.NextAsync(currentPropertyValue, cancellationToken);
            });
        }