必须填写至少10个字的日志
nnhy authored at 2012-07-27 18:48:21
22.38 KiB
X
using System;
using System.Collections.Generic;
using System.Web.UI;
using System.Web.UI.WebControls;
using NewLife.Reflection;
using NewLife.Web;
using XCode.Common;
using XCode.Configuration;

namespace XCode.Accessors
{
    /// <summary>WebForm实体访问器</summary>
    public class WebFormEntityAccessor : EntityAccessorBase
    {
        #region 属性
        /// <summary>种类</summary>
        public override EntityAccessorTypes Kind { get { return EntityAccessorTypes.WebForm; } }

        private Control _Container;
        /// <summary>页面</summary>
        public Control Container
        {
            get { return _Container; }
            private set { _Container = value; }
        }

        private Int64 _MaxLength = 10 * 1024 * 1024;
        /// <summary>最大文件大小,默认10M</summary>
        public Int64 MaxLength
        {
            get { return _MaxLength; }
            set { _MaxLength = value; }
        }

        private String _ItemPrefix = "frm";
        /// <summary>前缀</summary>
        public String ItemPrefix
        {
            get { return _ItemPrefix; }
            set { _ItemPrefix = value; }
        }

        #endregion

        #region 设置

        /// <summary>设置参数。返回自身,方便链式写法。</summary>
        /// <param name="name">参数名</param>
        /// <param name="value">参数值</param>
        /// <returns></returns>
        public override IEntityAccessor SetConfig(string name, object value)
        {
            if (name.EqualIgnoreCase(EntityAccessorOptions.Container))
                Container = value as Control;
            else if (name.EqualIgnoreCase(EntityAccessorOptions.MaxLength))
                MaxLength = (Int64)value;
            else if (name.EqualIgnoreCase(EntityAccessorOptions.ItemPrefix))
                ItemPrefix = (String)value;

            return base.SetConfig(name, value);
        }

        #endregion

        #region 读取
        /// <summary>外部=>实体,从外部读取指定实体字段的信息</summary>
        /// <param name="entity">实体对象</param>
        /// <param name="item">实体字段</param>
        protected override void ReadItem(IEntity entity, FieldItem item)
        {
            Control control = FindControlByField(item);
            if (control == null) return;

            //try
            //{
            GetFormItem(entity, item, control);
            //}
            //catch (Exception ex)
            //{
            //    throw new XCodeException("读取" + item.Name + "的数据时出错!" + ex.Message, ex);
            //}
        }

        /// <summary>把控件的值设置到实体属性上</summary>
        /// <param name="entity"></param>
        /// <param name="field"></param>
        /// <param name="control"></param>
        protected virtual void GetFormItem(IEntity entity, FieldItem field, Control control)
        {
            if (field == null || control == null) return;

            if (control is WebControl)
            {
                var wc = control as WebControl;

                // 分控件处理
                if (wc is TextBox)
                    GetFormItemTextBox(entity, field, wc as TextBox);
                else if (wc is Label)
                    GetFormItemLabel(entity, field, wc as Label);
                else if (wc is RadioButton)
                    GetFormItemRadioButton(entity, field, wc as RadioButton);
                else if (wc is CheckBox)
                    GetFormItemCheckBox(entity, field, wc as CheckBox);
                else if (wc is ListControl)
                    GetFormItemListControl(entity, field, wc as ListControl);
                // 不处理文件上传
                else if (wc is FileUpload)
                    return;
                else
                {
                    Object v = null;
                    if (GetControlValue(control, out v) && !Object.Equals(entity[field.Name], v)) SetEntityItem(entity, field, v);
                }
            }
            else
            {
                Object v = null;
                if (GetControlValue(control, out v) && !Object.Equals(entity[field.Name], v)) SetEntityItem(entity, field, v);
            }
        }

        private void SetEntityItem(IEntity entity, FieldItem field, Object value)
        {
            // 先转为目标类型
            value = TypeX.ChangeType(value, field.Type);
            // 如果是字符串,并且为空,则让它等于实体里面的值,避免影响脏数据
            if (field.Type == typeof(String) && String.IsNullOrEmpty((String)value) && String.IsNullOrEmpty((String)entity[field.Name])) value = entity[field.Name];
            entity.SetItem(field.Name, value);
        }

        /// <summary>文本框</summary>
        /// <param name="entity"></param>
        /// <param name="field"></param>
        /// <param name="control"></param>
        protected virtual void GetFormItemTextBox(IEntity entity, FieldItem field, TextBox control)
        {
            //String v = control.Text;
            //if (!Object.Equals(entity[field.Name], v)) SetEntityItem(field, v);

            Object v = null;
            if (!GetControlValue(control, out v)) v = control.Text;
            if (!Object.Equals(entity[field.Name], v))
            {
                // 如果是密码输入框,并且为空,不需要设置
                if (!String.IsNullOrEmpty("" + v) || control.TextMode != TextBoxMode.Password) SetEntityItem(entity, field, v);
            }
        }

        /// <summary>标签,不做任何操作</summary>
        /// <param name="entity"></param>
        /// <param name="field"></param>
        /// <param name="control"></param>
        protected virtual void GetFormItemLabel(IEntity entity, FieldItem field, Label control)
        {
        }

        /// <summary>复选框</summary>
        /// <param name="entity"></param>
        /// <param name="field"></param>
        /// <param name="control"></param>
        protected virtual void GetFormItemCheckBox(IEntity entity, FieldItem field, CheckBox control)
        {
            Type type = field.Type;
            Object v;
            if (type == typeof(Boolean))
                v = control.Checked;
            else if (type == typeof(Int32))
                v = control.Checked ? 1 : 0;
            else
                v = control.Checked;

            if (!Object.Equals(entity[field.Name], v)) SetEntityItem(entity, field, v);
        }

        /// <summary>列表框</summary>
        /// <param name="entity"></param>
        /// <param name="field"></param>
        /// <param name="control"></param>
        protected virtual void GetFormItemListControl(IEntity entity, FieldItem field, ListControl control)
        {
            //if (String.IsNullOrEmpty(control.SelectedValue)) return;

            String v = control.SelectedValue;
            if (!Object.Equals(entity[field.Name], v)) SetEntityItem(entity, field, v);
        }

        /// <summary>单选框</summary>
        /// <param name="entity"></param>
        /// <param name="field"></param>
        /// <param name="control"></param>
        protected virtual void GetFormItemRadioButton(IEntity entity, FieldItem field, RadioButton control)
        {
            List<RadioButton> list = new List<RadioButton>();
            // 找到同一级同组名的所有单选
            foreach (Control item in control.Parent.Controls)
            {
                if (!(item is RadioButton)) continue;

                RadioButton rb = item as RadioButton;
                if (rb.GroupName != control.GroupName) continue;

                list.Add(rb);
            }
            if (list.Count < 1) return;

            // 特殊处理数字
            if (field.Type == typeof(Int32))
            {
                Int32 id = -1;
                for (int i = 0; i < list.Count; i++)
                {
                    if (list[i].Checked)
                    {
                        id = i;
                        break;
                    }
                }
                if (id >= 0 && !Object.Equals(entity[field.Name], id)) SetEntityItem(entity, field, id);
            }
            else
            {
                foreach (RadioButton item in list)
                {
                    if (item.Checked)
                    {
                        if (!Object.Equals(entity[field.Name], item.Text))
                        {
                            SetEntityItem(entity, field, item.Text);
                            break;
                        }
                    }
                }
            }
        }
        #endregion

        #region 写入
        /// <summary>实体=>外部,把指定实体字段的信息写入到外部</summary>
        /// <param name="entity">实体对象</param>
        /// <param name="item">实体字段</param>
        protected override void WriteItem(IEntity entity, FieldItem item)
        {
            Control control = FindControlByField(item);
            if (control == null) return;

            Boolean canSave = true;
            //try
            //{
            SetFormItem(entity, item, control, canSave);
            //}
            //catch (Exception ex)
            //{
            //    throw new XCodeException("设置" + item.Name + "的数据时出错!" + ex.Message, ex);
            //}
        }

        /// <summary>设置控件的ToolTip提示信息</summary>
        /// <param name="field"></param>
        /// <param name="control"></param>
        protected virtual void SetToolTip(FieldItem field, Control control)
        {
            if (field == null || control == null) return;

            String toolTip = field.DisplayName;
            if (field.IsNullable)
                toolTip = String.Format("请填写{0}!", toolTip);
            else
                toolTip = String.Format("必须填写{0}!", toolTip);

            //if (control is Label) toolTip = null;
            if (control is Label) return;

            if (control is WebControl)
            {
                var wc = control as WebControl;

                // 设置ToolTip
                if (String.IsNullOrEmpty(wc.ToolTip) && !String.IsNullOrEmpty(toolTip)) wc.ToolTip = toolTip;
            }
            else
            {
                var pix = PropertyInfoX.Create(control.GetType(), "ToolTip");
                if (pix != null && String.IsNullOrEmpty((String)pix.GetValue(control)))
                {
                    pix.SetValue(control, toolTip);
                }
            }
        }

        /// <summary>把实体成员的值设置到控件上</summary>
        /// <param name="entity"></param>
        /// <param name="field"></param>
        /// <param name="control"></param>
        /// <param name="canSave"></param>
        protected virtual void SetFormItem(IEntity entity, FieldItem field, Control control, Boolean canSave)
        {
            if (field == null || control == null) return;

            if (control is WebControl)
            {
                var wc = control as WebControl;

                //// 必填项
                //if (!field.IsNullable) SetNotAllowNull(field, control, canSave);

                // 设置只读,只有不能保存时才设置,因为一般都不是只读,而前端可能自己设置了控件为只读,这种情况下这里再设置就会修改前端的意思
                if (!canSave)
                {
                    if (wc is TextBox)
                        (wc as TextBox).ReadOnly = !canSave;
                    else
                        wc.Enabled = canSave;
                }

                // 分控件处理
                if (wc is TextBox)
                    SetFormItemTextBox(entity, field, wc as TextBox, canSave);
                else if (wc is Label)
                    SetFormItemLabel(entity, field, wc as Label, canSave);
                else if (wc is RadioButton)
                    SetFormItemRadioButton(entity, field, wc as RadioButton, canSave);
                else if (wc is CheckBox)
                    SetFormItemCheckBox(entity, field, wc as CheckBox, canSave);
                else if (wc is ListControl)
                    SetFormItemListControl(entity, field, wc as ListControl, canSave);
                // 不处理文件上传
                else if (wc is FileUpload)
                    return;
                else
                {
                    SetControlValue(control, entity[field.Name]);
                }
            }
            else
            {
                SetControlValue(control, entity[field.Name]);
            }
        }

        /// <summary>文本框</summary>
        /// <param name="entity"></param>
        /// <param name="field"></param>
        /// <param name="control"></param>
        /// <param name="canSave"></param>
        protected virtual void SetFormItemTextBox(IEntity entity, FieldItem field, TextBox control, Boolean canSave)
        {
            Type type = field.Type;
            Object value = entity[field.Name];
            if (type == typeof(DateTime))
            {
                DateTime d = (DateTime)value;
                // 有时候可能并不需要默认时间
                //if (Helper.IsEntityNullKey(entity) && d == DateTime.MinValue) d = DateTime.Now;
                value = d.ToString("yyyy-MM-dd HH:mm:ss");
            }

            if (!SetControlValue(control, value)) control.Text = value != null ? value.ToString() : "";
        }

        /// <summary>标签</summary>
        /// <param name="entity"></param>
        /// <param name="field"></param>
        /// <param name="control"></param>
        /// <param name="canSave"></param>
        protected virtual void SetFormItemLabel(IEntity entity, FieldItem field, Label control, Boolean canSave)
        {
            Type type = field.Type;
            if (type == typeof(DateTime))
            {
                DateTime d = (DateTime)entity[field.Name];
                if (Helper.IsEntityNullKey(entity) && d == DateTime.MinValue) d = DateTime.Now;
                control.Text = d.ToString("yyyy-MM-dd HH:mm:ss");
            }
            else if (type == typeof(Decimal))
            {
                Decimal d = (Decimal)entity[field.Name];
                control.Text = d.ToString("c");
            }
            else
                control.Text = String.Empty + entity[field.Name];
        }

        /// <summary>复选框</summary>
        /// <param name="entity"></param>
        /// <param name="field"></param>
        /// <param name="control"></param>
        /// <param name="canSave"></param>
        protected virtual void SetFormItemCheckBox(IEntity entity, FieldItem field, CheckBox control, Boolean canSave)
        {
            Type type = field.Type;
            if (type == typeof(Boolean))
                control.Checked = (Boolean)entity[field.Name];
            else if (type == typeof(Int32))
                control.Checked = (Int32)entity[field.Name] != 0;
            else
                control.Checked = entity[field.Name] != null;
        }

        /// <summary>列表框</summary>
        /// <param name="entity"></param>
        /// <param name="field"></param>
        /// <param name="control"></param>
        /// <param name="canSave"></param>
        protected virtual void SetFormItemListControl(IEntity entity, FieldItem field, ListControl control, Boolean canSave)
        {
            if (control.Items.Count < 1 || !String.IsNullOrEmpty(control.DataSourceID))
            {
                control.DataBind();
                // 这个赋值会影响RequiresDataBinding,而RequiresDataBinding会导致列表控件在OnPreRender阶段重新绑定,造成当前设定的值丢失。
                //control.AppendDataBoundItems = false;
            }
            if (control.Items.Count < 1) return;

            String value = String.Empty + entity[field.Name];
            try
            {
                control.SelectedValue = value;
                if (control.GetType() == typeof(DropDownList) || control.GetType() == typeof(ListControl))
                {
                    /*
                     * 对于ListControl和DropDownList,仅PostBack时有可能抛出异常,初次打开有可能在PerformDataBinding中抛出异常,所以要做额外检测
                     *
                     * 因为DropDownList.SelectedIndex get时有可能修改Items[0].Selected, 所以下面代码最好避免访问SelectedIndex,SelectedValue
                     *
                     * 对于XControl.DropDownList始终没问题
                     * */

                    var selected = false;
                    for (int i = 0; i < control.Items.Count; i++)
                    {
                        var item = control.Items[i];
                        if (item.Selected)
                        {
                            selected = item.Value == value;
                            break;
                        }
                    }
                    if (!selected)
                    {
                        // 没有任何选中项或选中项不是设置的值
                        throw new ArgumentException();
                    }
                }
            }
            catch (ArgumentException)
            {
                var li = control.Items.FindByValue(value);
                if (li == null)
                {
                    li = new ListItem(value, value);
                    control.Items.Add(li);
                }
                control.ClearSelection();
                li.Selected = true;
            }
        }

        /// <summary>单选框</summary>
        /// <param name="entity"></param>
        /// <param name="field"></param>
        /// <param name="control"></param>
        /// <param name="canSave"></param>
        protected virtual void SetFormItemRadioButton(IEntity entity, FieldItem field, RadioButton control, Boolean canSave)
        {
            List<RadioButton> list = new List<RadioButton>();
            // 找到同一级同组名的所有单选
            foreach (Control item in control.Parent.Controls)
            {
                if (!(item is RadioButton)) continue;

                RadioButton rb = item as RadioButton;
                if (rb.GroupName != control.GroupName) continue;

                list.Add(rb);
            }
            if (list.Count < 1) return;

            // 特殊处理数字
            if (field.Type == typeof(Int32))
            {
                Int32 id = (Int32)entity[field.Name];
                if (id < 0 || id >= list.Count) id = 0;
                for (int i = 0; i < list.Count; i++)
                {
                    list[i].Checked = (i == id);
                }
            }
            else
            {
                String value = String.Empty + entity[field.Name];

                foreach (RadioButton item in list)
                {
                    item.Checked = item.Text == value;
                }
            }
        }

        /// <summary>设置控件的不允许空</summary>
        /// <param name="field"></param>
        /// <param name="control"></param>
        /// <param name="canSave"></param>
        protected virtual void SetNotAllowNull(FieldItem field, Control control, Boolean canSave)
        {
            if (field.IsNullable) return;
            // Label后面不需要
            if (control is Label) return;

            var lc = new LiteralControl();
            lc.Text = "<font style='color:#FF0000;font-size:16pt;'> *</font>";

            Int32 p = control.Parent.Controls.IndexOf(control);
            // 有时候可能无法添加,但是不影响使用,应该屏蔽异常
            try
            {
                control.Parent.Controls.AddAt(p + 1, lc);
            }
            catch { }
        }
        #endregion

        #region 辅助
        private static Boolean GetControlValue(Control control, out Object value)
        {
            TypeX tx = control.GetType();
            String name = tx.GetCustomAttributeValue<ControlValuePropertyAttribute, String>();
            PropertyInfoX pix = null;
            if (!String.IsNullOrEmpty(name)) pix = PropertyInfoX.Create(tx.Type, name);
            if (pix == null) pix = PropertyInfoX.Create(tx.Type, "Value");
            if (pix == null) pix = PropertyInfoX.Create(tx.Type, "Text");
            if (pix != null)
            {
                value = pix.GetValue(control);
                return true;
            }

            value = null;
            return false;
        }

        private static Boolean SetControlValue(Control control, Object value)
        {
            TypeX tx = control.GetType();
            String name = tx.GetCustomAttributeValue<ControlValuePropertyAttribute, String>();
            PropertyInfoX pix = null;
            if (!String.IsNullOrEmpty(name)) pix = PropertyInfoX.Create(tx.Type, name);
            if (pix == null) pix = PropertyInfoX.Create(tx.Type, "Value");
            if (pix == null) pix = PropertyInfoX.Create(tx.Type, "Text");
            if (pix != null)
            {
                if (value == null && pix.Type.IsValueType) return false;
                pix.SetValue(control, value);
                return true;
            }

            return false;
        }

        /// <summary>查找表单控件</summary>
        /// <param name="id"></param>
        /// <returns></returns>
        protected virtual Control FindControl(string id)
        {
            Control control = ControlHelper.FindControlByField<Control>(Container, id);
            if (control != null) return control;

            control = Container.FindControl(id);
            if (control != null) return control;

            return ControlHelper.FindControl<Control>(Container, id);
        }

        /// <summary>查找字段对应的控件</summary>
        /// <param name="field"></param>
        /// <returns></returns>
        protected virtual Control FindControlByField(FieldItem field)
        {
            return FindControl(ItemPrefix + field.Name);
        }
        #endregion
    }
}