ASP.NET FormView - 动态模版以及数据绑定到DynamicObject

来源:互联网 发布:奥塔哥大学 知乎 编辑:程序博客网 时间:2024/06/05 18:37

需求:通过metadata数据源构造一个实体,实体属性为动态(metadata可变),使用FormView实现实体的CRUD功能

问题1:如何实现FormView的动态ItemTemplate,EditItemTemplate,InsertItemTemplate

解决1:自定义模版类,实现IBindableTemplate接口

参考:如何实现自定义模版

            http://www.intelligiblebabble.com/dynamically-create-item-templates-server-side/

            http://www.developerfusion.com/code/4721/dynamically-loading-an-ibindabletemplate/

            如何实现模版字段的数据绑定:

             http://forums.asp.net/t/1783767.aspx/2/10

     http://forums.asp.net/t/911217.aspx/2/10?Creating+GridView+at+Runtime+Columns+from+Database


问题2:如何实现前述动态模版的数据绑定

解决2:使用自.NET 4.0推出的DynamicObject,将模版字段绑定到DynamicObject上的动态属性

参考: 

如何将Dictionary转换为ExpandoObject (一种DynamicObject) http://stackoverflow.com/questions/7595416/convert-dictionarystring-object-to-anonymous-object

解决ExpandoObject无法使用DataBinder.Eval的问题  http://programcsharp.com/blog/archive/2012/09/25/databinder-eval-expandoobject-custom-typedescriptor.aspx


实现自定义模版类DynamicItemTemplate,支持ReadOnly 或者Update/Insert模式

public class DynamicItemTemplate : IBindableTemplate    {        private List<CustomFieldMetadata> _fields;        private bool _isReadOnly;         public DynamicItemTemplate(List<CustomFieldMetadata> fields, bool readOnly)        {            _fields = fields;            _isReadOnly = readOnly;        }         public void InstantiateIn(Control container)        {            var divFormWrapper = new HtmlGenericControl("div");            divFormWrapper.Attributes.Add("class""form-wrapper");                         var divWrapPanel = new HtmlGenericControl("div");            divWrapPanel.Attributes.Add("class""wrap-panel");             divFormWrapper.Controls.Add(divWrapPanel);             foreach(var f in _fields)            {                if (f.Name == "id"//ignore "id" field                {                    continue;                }                                var label = new HtmlGenericControl("span");                label.Attributes.Add("class""label");                label.InnerText = f.Name;                                divWrapPanel.Controls.Add(label);                 if (_isReadOnly)                {                    Label value = new Label { ID = f.Name };//control id must to be field name                    divWrapPanel.Controls.Add(value);                    value.DataBinding += Field_DataBinding;                }                else                {                    var span = new HtmlGenericControl("span");                    var input = CreateFiledInput(f); //control id must to be field name                    span.Controls.Add(input);                    divWrapPanel.Controls.Add(span);                     input.DataBinding += Field_DataBinding;                }            }            container.Controls.Add(divFormWrapper);        }         void Field_DataBinding(object sender, EventArgs e)        {            if (sender is Label)            {                Label label = sender as Label;                object databoundValue = DataBinder.Eval(((IDataItemContainer)((Control)sender).NamingContainer).DataItem, label.ID); //assuming input control id is the property name of the bound data item                if (databoundValue != null)                {                    label.Text = databoundValue.ToString();                }                            }            else             {                Control control = sender as Control;                object databoundValue = DataBinder.Eval(((IDataItemContainer)((Control)sender).NamingContainer).DataItem, control.ID); //assuming input control id is the property name of the bound data item                if (databoundValue != null)                {                    if (control is ITextControl)                    {                        ((ITextControl)control).Text = databoundValue.ToString();                    }                    else if (control is RadDatePicker)                    {                        DateTime dt;                        DateTime.TryParseExact(databoundValue.ToString(), "yyyy-MM-dd"null, System.Globalization.DateTimeStyles.None, out dt);                        ((RadDatePicker)control).SelectedDate = dt;                    }                }            }        }         public System.Collections.Specialized.IOrderedDictionary ExtractValues(Control container)        {            if (_isReadOnly)            {                return null;            }            OrderedDictionary dict = new OrderedDictionary();            foreach (var f in _fields)            {                var control = container.FindControl(f.Name);                if (control is ITextControl)                {                     dict.Add(control.ID, ((ITextControl)control).Text);                }                else if (control is RadDatePicker)                {                    dict.Add(control.ID, ((RadDatePicker)control).SelectedDate);                }                            }            return dict;        }         public Control CreateFiledInput(CustomFieldMetadata fieldMetadata)        {            Control control = null;            switch(fieldMetadata.Type)            {                case CustomFieldTypeDataSourceProvider.TEXT:                    control = new RadTextBox();                    break;                case CustomFieldTypeDataSourceProvider.INTEGER:                case CustomFieldTypeDataSourceProvider.DECIMAL:                    control = new RadNumericTextBox();                    break;                case CustomFieldTypeDataSourceProvider.DATE:                    control = new RadDatePicker();                    break;            }            control.ID = fieldMetadata.Name;//set control id to be field name            return control;        }     }
            


在 FormView 控件所在的页面Init 事件处理中,初始化FormView的模版:

 var fields = GetCustomFields();

 DynamicItemTemplate itemTemplate = new DynamicItemTemplate(fields, true); detailForm.ItemTemplate = itemTemplate; DynamicItemTemplate editItemTemplate = new DynamicItemTemplate(fields, false); detailForm.EditItemTemplate = editItemTemplate;

加载FormView数据的Select方法实现如下:

 public dynamic Select([Sessionstring id)        {            if (id == null)            {                return null;            }            Dictionary<stringobject> fields = SelectRaw(id);//entity values as a Dictionary             var names = fields.Keys.ToList();            var item = DynamicDataBindHelper.ConvertToBindableDynamicObject(fields);            return item;        }


将ExpandoObject转换为可用于FormView数据绑定的对象, (DynamicTypeDescriptorWrapper实现来自于前述引用)

 public class DynamicDataBindHelper    {        public static dynamic ConvertToBindableDynamicObject(Dictionary<stringobject> dictionary)        {            var expando = new ExpandoObject();            var collection = (ICollection<KeyValuePair<stringobject>>)expando;            foreach (var pair in dictionary)            {                collection.Add(pair);            }            dynamic dynamaicObject = new DynamicTypeDescriptorWrapper(expando);            return dynamaicObject;        }    }



原创粉丝点击