/// <summary>
        /// Create a collection of <see cref="PropertyDefinition"/> to configure how to create decorate class and clone objects into new types from original query results.
        /// </summary>
        /// <param name="dynamicPageService"></param>
        /// <returns></returns>
        private static IDictionary<PropertyDefinition, string> CreatePropertyDecorateConfigs(IDynamicPage dynamicPageService)
        {
            GridViewPanelConfiguration gridViewPanel = dynamicPageService.Configuration.Panels.FirstOrDefault(p => p.PanelType == DynamicPagePanelTypes.GridViewPanel) as GridViewPanelConfiguration;
            if (gridViewPanel == null)
                return new Dictionary<PropertyDefinition, string>();

            Dictionary<PropertyDefinition, string> results = new Dictionary<PropertyDefinition, string>();

            ExtGridConfiguration extGridConfiguration = ExtGridConfigurationResolver.Resolve();

            // Add wrappers for original properties
            for (int index = 0; index < gridViewPanel.Fields.Count; index++)
            {
                if (extGridConfiguration != null)
                {
                    int findingColumnIndex = index + 1;
                    if (gridViewPanel.EnabledCheckBoxField) findingColumnIndex++;
                    ExtGridColumnConfiguration extGridColumnConfiguration = extGridConfiguration.Columns.FirstOrDefault(col => col.ColumnIndex == findingColumnIndex);
                    if (extGridColumnConfiguration == null || extGridColumnConfiguration.Hidden) continue;
                }

                GridViewFieldConfiguration gridViewField = gridViewPanel.Fields[index];
                PropertyDefinition propertyDecorateConfig = new PropertyDefinition(typeof(string))
                {
                    PropertyName = gridViewField.FieldName,
                    NewPropertyName = FieldNameTransformUtility.DataBoundFieldName(gridViewField.FieldName, index)
                };

                GridViewFieldValueTransformConfiguration transformer = gridViewField.Transformer;
                if (transformer != null && transformer.TransformType != GridViewFieldValueTransformTypes.None)
                {
                    propertyDecorateConfig.PropertyValueConvertCallback = arg => { return TransformFieldValue(transformer, gridViewField.FieldName, arg); };
                }
                else
                {
                    propertyDecorateConfig.PropertyValueConvertCallback = arg =>
                    {
                        if (!(arg is string) && arg is IEnumerable) return arg;
                        return arg != null ? arg.ToString() : "";
                    };
                }

                results.Add(propertyDecorateConfig, gridViewField.HeaderText);
            }

            // Add wrapper for row view property.
            if (gridViewPanel.RowView != null)
            {
                results.Add(new PropertyDefinition(typeof(string))
                {
                    PropertyName = gridViewPanel.RowView.FieldName,
                    NewPropertyName = FieldNameTransformUtility.ViewFragmentFieldName(gridViewPanel.RowView.FieldName),
                    PropertyValueConvertCallback = (arg) => { return arg != null ? arg.ToString() : ""; }
                }, Resources.DP_RowView_HeaderText);
            }

            return results;
        }
        /// <summary>
        /// Create a collection of <see cref="PropertyDefinition"/> to configure how to create decorate class and clone objects into new types from original query results.
        /// </summary>
        /// <param name="dynamicPageService"></param>
        /// <returns></returns>
        private static IEnumerable<PropertyDefinition> CreatePropertyDecorateConfigs(IDynamicPage dynamicPageService)
        {
            GridViewPanelConfiguration gridViewPanel = dynamicPageService.Configuration.Panels.FirstOrDefault(p => p.PanelType == DynamicPagePanelTypes.GridViewPanel) as GridViewPanelConfiguration;
            if (gridViewPanel == null)
                return new PropertyDefinition[0];

            Collection<PropertyDefinition> results = new Collection<PropertyDefinition>();
            results.Add(new PropertyDefinition(typeof(string)) { PropertyName = gridViewPanel.PrimaryKeyFieldName, NewPropertyName = FieldNameTransformUtility.PrimaryKeyFieldName(gridViewPanel.PrimaryKeyFieldName) });

            // Add wrappers for original properties
            for (int index = 0; index < gridViewPanel.Fields.Count; index++)
            {
                GridViewFieldConfiguration gridViewField = gridViewPanel.Fields[index];
                PropertyDefinition propertyDecorateConfig = new PropertyDefinition(typeof(string))
                {
                    PropertyName = gridViewField.FieldName,
                    NewPropertyName = FieldNameTransformUtility.DataBoundFieldName(gridViewField.FieldName, index)
                };

                GridViewFieldValueTransformConfiguration transformer = gridViewField.Transformer;
                if (transformer != null && transformer.TransformType != GridViewFieldValueTransformTypes.None)
                {
                    propertyDecorateConfig.PropertyValueConvertCallback = arg => { return TransformFieldValue(transformer, gridViewField.FieldName, arg); };
                }
                else
                {
                    propertyDecorateConfig.PropertyValueConvertCallback = arg =>
                    {
                        if (!(arg is string) && arg is IEnumerable) return arg;
                        return arg != null ? arg.ToString() : "";
                    };
                }

                results.Add(propertyDecorateConfig);
            }

            // Add wrapper for row view property.
            if (gridViewPanel.RowView != null)
            {
                results.Add(new PropertyDefinition(typeof(string))
                {
                    PropertyName = gridViewPanel.RowView.FieldName,
                    NewPropertyName = FieldNameTransformUtility.ViewFragmentFieldName(gridViewPanel.RowView.FieldName),
                    PropertyValueConvertCallback = (arg) => { return arg != null ? arg.ToString() : ""; }
                });
            }

            // Add wrapper for ShowCheckBox
            results.Add(new PropertyDefinition(typeof(bool))
            {
                PropertyName = null,
                NewPropertyName = DynamicPageDataServiceHandler.ShowCheckBoxColumnPropertyName,
                PropertyValueConvertCallback = (arg) => { return gridViewPanel.EnabledCheckBoxField; }
            });

            // Add wrapper for EditButton
            results.Add(new PropertyDefinition(typeof(bool))
            {
                PropertyName = null,
                NewPropertyName = DynamicPageDataServiceHandler.ShowEditButtonColumnPropertyName,
                PropertyValueConvertCallback = (arg) => { return gridViewPanel.EditButton != null; }
            });

            // Add wrapper for ViewButton
            results.Add(new PropertyDefinition(typeof(bool))
            {
                PropertyName = null,
                NewPropertyName = DynamicPageDataServiceHandler.ShowViewButtonColumnPropertyName,
                PropertyValueConvertCallback = (arg) => { return gridViewPanel.ViewButton != null; }
            });

            // Add wrapper for DeleteButton
            results.Add(new PropertyDefinition(typeof(bool))
            {
                PropertyName = null,
                NewPropertyName = DynamicPageDataServiceHandler.ShowDeleteButtonColumnPropertyName,
                PropertyValueConvertCallback = (arg) => { return gridViewPanel.DeleteButton != null; }
            });

            return results;
        }
        public void CreateDecorateTypeTest()
        {
            var anonymousObject = new { Name = "Eunge Liu", Career = "Software Development", Birthday = new DateTime(1982, 2, 7) };
            Type anonymousType = anonymousObject.GetType();

            IEnumerable<PropertyDefinition> propertyDecorateConfigs = new PropertyDefinition[]
            {
                new PropertyDefinition("Name") { NewPropertyName = "Name" },
                new PropertyDefinition("Career") { NewPropertyName = "Career" },
                new PropertyDefinition("Birthday") { NewPropertyName = "Birthday" },
            };

            Type decorateType = ClassDecorator.CreateDecorateType(anonymousType.Name, propertyDecorateConfigs);
            Assert.IsNotNull(decorateType);

            PropertyInfo[] propertyInfoArray = decorateType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
            Assert.AreEqual(3, propertyInfoArray.Length, "There should be three properties generated in decorate class.");
        }
        public void CreateComplexDecorateObjectsTest()
        {
            string[] bindingPropertyNames = new string[] { "Name", "SubObject.Category", "Properties[\"Ext\"].Category", "[\"Com\"].Category", "[\"Com\"].Description" };
            CodeDomTestObject fixture = new CodeDomTestObject
            {
                Name = "Eunge",
                SubObject = new SubCodeDomTestObject { Category = "NUnit", Description = "Desc" },
            };

            fixture["Com"] = new SubCodeDomTestObject { Category = "Com.NUnit", Description = "Com.Desc" };
            fixture.Properties["Ext"] = new SubCodeDomTestObject { Category = "Ext.NUnit", Description = "Ext.Desc" };

            Collection<PropertyDefinition> configs = new Collection<PropertyDefinition>();
            // Add wrappers for original properties
            Dictionary<string, string> cachedFieldNames = new Dictionary<string,string>();
            int index = 0;
            foreach (string bindingPropertyName in bindingPropertyNames)
            {
                PropertyDefinition config = new PropertyDefinition(typeof(string))
                {
                    PropertyName = bindingPropertyName,
                    NewPropertyName = FieldNameTransformUtility.DataBoundFieldName(bindingPropertyName, index++),
                };

                cachedFieldNames[bindingPropertyName]=config.NewPropertyName;
                configs.Add(config);
            }

            IEnumerable outputs = ClassDecorator.CreateDecorateObjects(new[] { fixture }, configs);
            object outputObject = outputs.Cast<object>().First();
            Assert.AreEqual("Eunge", DataBinder.Eval(outputObject, cachedFieldNames["Name"]));
            Assert.AreEqual("NUnit", DataBinder.Eval(outputObject, cachedFieldNames["SubObject.Category"]));
            Assert.AreEqual("Ext.NUnit", DataBinder.Eval(outputObject, cachedFieldNames["Properties[\"Ext\"].Category"]));
            Assert.AreEqual("Com.NUnit", DataBinder.Eval(outputObject, cachedFieldNames["[\"Com\"].Category"]));
            Assert.AreEqual("Com.Desc", DataBinder.Eval(outputObject, cachedFieldNames["[\"Com\"].Description"]));
        }
        public void CreateDecorateObjectsWithoutConvertPropertyTypesTest()
        {
            var anonymousObjects = new[]
            {
                new { Name = "Eunge Liu", Career = "Software Development", Birthday = new DateTime(1982, 2, 7) },
                new { Name = "Lucy Liu", Career = "Financial", Birthday = new DateTime(1982, 5, 1) }
            };

            IEnumerable<PropertyDefinition> propertyDecorateConfigs = new PropertyDefinition[]
            {
                new PropertyDefinition(typeof(string)) { PropertyName = "Name", NewPropertyName = "Name" },
                new PropertyDefinition(typeof(string)) { PropertyName = "Career", NewPropertyName = "Career" },
                new PropertyDefinition(typeof(DateTime)) { PropertyName = "Birthday", NewPropertyName = "Birthday" },
            };

            IEnumerable<object> returnObjects = ClassDecorator.CreateDecorateObjects(anonymousObjects, propertyDecorateConfigs).Cast<object>();
            Assert.IsNotNull(returnObjects);
            Assert.AreEqual(2, returnObjects.Count());

            IObjectWrapper objectWrapper = new ObjectWrapper(returnObjects.First());
            Assert.AreEqual("Eunge Liu", objectWrapper.GetPropertyValue("Name"));
            Assert.AreEqual("Software Development", objectWrapper.GetPropertyValue("Career"));
            Assert.AreEqual(new DateTime(1982, 2, 7), objectWrapper.GetPropertyValue("Birthday"));

            objectWrapper = new ObjectWrapper(returnObjects.Last());
            Assert.AreEqual("Lucy Liu", objectWrapper.GetPropertyValue("Name"));
            Assert.AreEqual("Financial", objectWrapper.GetPropertyValue("Career"));
            Assert.AreEqual(new DateTime(1982, 5, 1), objectWrapper.GetPropertyValue("Birthday"));
        }