/// <summary>
        /// Ensures that the correct attribute filter controls are created based on the selected <see cref="StepType"/>.
        /// </summary>
        /// <param name="stepTypePicker">The <see cref="StepTypePicker"/>.</param>
        private void EnsureSelectedStepTypeControls(StepTypePicker stepTypePicker)
        {
            DynamicControlsPanel containerControl = stepTypePicker.Parent as DynamicControlsPanel;
            FilterField          filterControl    = containerControl.FirstParentControlOfType <FilterField>();

            // Get the EntityFields for the attributes associated with the selected StepType.
            var entityFields = GetStepAttributes(stepTypePicker.SelectedValueAsId());

            // Create the attribute selection dropdown.
            string           propertyControlId = string.Format("{0}_ddlProperty", containerControl.ID);
            RockDropDownList ddlProperty       = containerControl.Controls.OfType <RockDropDownList>().FirstOrDefault(a => a.ID == propertyControlId);

            if (ddlProperty == null)
            {
                ddlProperty                       = new RockDropDownList();
                ddlProperty.ID                    = propertyControlId;
                ddlProperty.AutoPostBack          = true;
                ddlProperty.SelectedIndexChanged += ddlProperty_SelectedIndexChanged;
                ddlProperty.AddCssClass("js-property-dropdown");
                containerControl.Controls.Add(ddlProperty);
            }

            // Clear the list of items.  We will rebuild them to match the selected StepType.
            ddlProperty.Items.Clear();

            // Add an empty option.
            ddlProperty.Items.Add(new ListItem());

            // Add a ListItem for each of the attributes.
            foreach (var entityField in entityFields)
            {
                ddlProperty.Items.Add(new ListItem(entityField.TitleWithoutQualifier, entityField.UniqueName));
            }

            if (stepTypePicker.Page.IsPostBack)
            {
                // If the attribute has been selected, make sure that value is retained.
                ddlProperty.SetValue(stepTypePicker.Page.Request.Params[ddlProperty.UniqueID]);
            }

            // Add the filter controls (comparison type and value).
            foreach (var entityField in entityFields)
            {
                string controlId = string.Format("{0}_{1}", containerControl.ID, entityField.UniqueName);
                if (!containerControl.Controls.OfType <Control>().Any(a => a.ID == controlId))
                {
                    var control = entityField.FieldType.Field.FilterControl(entityField.FieldConfig, controlId, true, filterControl.FilterMode);
                    if (control != null)
                    {
                        containerControl.Controls.Add(control);
                    }
                }
            }
        }
        /// <summary>
        /// Sets the selection.
        /// </summary>
        /// <param name="entityType"></param>
        /// <param name="controls">The controls.</param>
        /// <param name="selection">The selection.</param>
        public override void SetSelection(Type entityType, Control[] controls, string selection)
        {
            if (string.IsNullOrWhiteSpace(selection) || controls.Length <= 0)
            {
                return;
            }

            var values = JsonConvert.DeserializeObject <List <string> >(selection);

            if (values.Count <= 0)
            {
                return;
            }

            var stepType = GetStepType(values[1].AsGuid());

            if (stepType == null)
            {
                return;
            }

            var containerControl = controls[0] as DynamicControlsPanel;

            if (containerControl.Controls.Count > 0)
            {
                StepProgramPicker stepProgramPicker = containerControl.Controls[0] as StepProgramPicker;
                stepProgramPicker.SelectedValue = stepType.StepProgramId.ToString();
            }

            if (containerControl.Controls.Count > 1)
            {
                StepTypePicker stepTypePicker = containerControl.Controls[1] as StepTypePicker;
                stepTypePicker.StepProgramId = stepType.StepProgramId;
                stepTypePicker.SelectedValue = stepType.Id.ToString();

                EnsureSelectedStepTypeControls(stepTypePicker);
            }

            if (containerControl.Controls.Count > 2 && values.Count > 2)
            {
                DropDownList ddlProperty  = containerControl.Controls[2] as DropDownList;
                var          entityFields = GetStepAttributes(stepType.Id);

                var panelControls = new List <Control>();
                panelControls.AddRange(containerControl.Controls.OfType <Control>());
                SetEntityFieldSelection(entityFields, ddlProperty, values.Skip(2).ToList(), panelControls);
            }
        }
        /// <summary>
        /// Handles the SelectedIndexChanged event of the ddlProperty control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        protected void ddlProperty_SelectedIndexChanged(object sender, EventArgs e)
        {
            var            ddlProperty      = sender as RockDropDownList;
            var            containerControl = ddlProperty.FirstParentControlOfType <DynamicControlsPanel>();
            FilterField    filterControl    = ddlProperty.FirstParentControlOfType <FilterField>();
            StepTypePicker stepTypePicker   = filterControl.ControlsOfTypeRecursive <StepTypePicker>().Where(a => a.HasCssClass("js-step-type-picker")).FirstOrDefault();

            var entityFields = GetStepAttributes(stepTypePicker.SelectedValueAsId());
            var entityField  = entityFields.FirstOrDefault(a => a.UniqueName == ddlProperty.SelectedValue);

            if (entityField != null)
            {
                string controlId = string.Format("{0}_{1}", containerControl.ID, entityField.UniqueName);
                if (!containerControl.Controls.OfType <Control>().Any(a => a.ID == controlId))
                {
                    var control = entityField.FieldType.Field.FilterControl(entityField.FieldConfig, controlId, true, filterControl.FilterMode);
                    if (control != null)
                    {
                        // Add the filter controls of the selected field
                        containerControl.Controls.Add(control);
                    }
                }
            }
        }
        /// <summary>
        /// Creates the child controls.
        /// Implement this version of CreateChildControls if your DataFilterComponent supports different FilterModes
        /// </summary>
        /// <param name="entityType"></param>
        /// <param name="filterControl"></param>
        /// <param name="filterMode"></param>
        /// <returns></returns>
        public override Control[] CreateChildControls(Type entityType, FilterField filterControl, FilterMode filterMode)
        {
            // Create a container to hold our dynamic controls and add it to the FilterField.
            var containerControl = new DynamicControlsPanel
            {
                ID       = string.Format("{0}_containerControl", filterControl.ID),
                CssClass = "js-container-control"
            };

            filterControl.Controls.Add(containerControl);

            // Create the StepProgramPicker.
            StepProgramPicker stepProgramPicker = new StepProgramPicker
            {
                ID       = filterControl.ID + "_stepProgramPicker",
                Label    = "Step Program",
                Required = true
            };

            stepProgramPicker.SelectedIndexChanged += stepProgramPicker_SelectedIndexChanged;
            stepProgramPicker.AutoPostBack          = true;
            StepProgramPicker.LoadDropDownItems(stepProgramPicker, true);
            containerControl.Controls.Add(stepProgramPicker);

            // Create the StepTypePicker.
            StepTypePicker stepTypePicker = new StepTypePicker
            {
                ID       = filterControl.ID + "_stepTypePicker",
                CssClass = "js-step-type-picker",
                Label    = "Step Type",
                Required = true
            };

            stepTypePicker.SelectedIndexChanged += stepTypePicker_SelectedIndexChanged;
            stepTypePicker.AutoPostBack          = true;
            containerControl.Controls.Add(stepTypePicker);

            if (filterMode == FilterMode.SimpleFilter)
            {
                // we still need to render the control in order to get the selected StepProgramId on postback, so just hide it instead
                stepProgramPicker.Style[HtmlTextWriterStyle.Display] = "none";
                stepTypePicker.Style[HtmlTextWriterStyle.Display]    = "none";
            }

            if (filterControl.Page.IsPostBack)
            {
                // If the Step Program has already been selected, make sure it retains that value, and
                // set the StepProgramId of the StepTypePicker.
                var stepProgramId = filterControl.Page.Request.Params[stepProgramPicker.UniqueID];
                stepProgramPicker.SelectedValue = stepProgramId;
                stepTypePicker.StepProgramId    = stepProgramId.AsIntegerOrNull();

                // If the Step Type has already been selected, make sure it retains that value.
                var stepTypePickerId = filterControl.Page.Request.Params[stepTypePicker.UniqueID];
                stepTypePicker.SelectedValue = stepTypePickerId;

                // Ensure that the attribute filter controls are updated to reflect the current
                // Step Type selection.
                EnsureSelectedStepTypeControls(stepTypePicker);
            }

            return(new Control[] { containerControl });
        }