重写 ASP.NET Boundfield 以支持 Dropdownlist 缺少最后一项功能

发布于 2024-08-16 12:03:41 字数 3472 浏览 6 评论 0原文

如果我把它放在 Gridview 中,我设法覆盖 Boundfield 以显示下拉列表。

protected override void InitializeDataCell(DataControlFieldCell cell, DataControlRowState rowState)
    {
        Control child = null;
        Control cellControl = null;

        if ((((rowState & DataControlRowState.Edit) != DataControlRowState.Normal) && !this.ReadOnly) 
            || ((rowState & DataControlRowState.Insert) != DataControlRowState.Normal))
        {
            // If data cell is in edit mode, create DropDownList editor for this cell
            // and set data properties.
            
            DropDownList box = new DropDownList();                
            box.Items.Add(DefaultValueText);               

            box.DataSource = this.GetDataSource();
            box.DataMember = this.BusinessObjectName;
            box.DataTextField = this.DataTextField;
            box.DataValueField = this.DataValueField;
            box.AppendDataBoundItems = true;
            box.ToolTip = this.HeaderText;

            cell.Controls.Add(box);
            box.DataBind();
            // if in edit mode, prepare dropdown for binding
            if ((this.DataField.Length != 0) && ((rowState & DataControlRowState.Edit) != DataControlRowState.Normal))
            {
                cellControl = box;
            }
        }
        else if (this.DataField.Length != 0)    // if in read only mode, prepare cell for binding
        {
            cellControl = cell;
        }

        if ((cellControl != null) && base.Visible)
        {
            cellControl.DataBinding += new EventHandler(this.OnDataBindField);
        }
    }
    

    protected override void OnDataBindField(object sender, EventArgs e)
    {
        Control control = (Control)sender;
        Control namingContainer = control.NamingContainer;
        object dataValue = this.GetValue(namingContainer);
        bool encode = (this.SupportsHtmlEncode && this.HtmlEncode) && (control is TableCell);
        string str = this.FormatDataValue(dataValue, encode);
        if (control is TableCell)
        {
            if (str.Length == 0)
            {
                str = " ";
            }
            ((TableCell)control).Text = str;
        }
        else
        {
            //If data cell is in edit mode, set selected value of DropDownList 
            if (dataValue != null)
            {
                DropDownList dropDownList = (DropDownList) control;
                
                ListItem itm = dropDownList.Items.FindByText(dataValue.ToString());
                if (itm != null)
                {
                    dropDownList.Text = itm.Value;
                }
                else
                    ((DropDownList)control).Text = DefaultValueText;
            }
        }
    }

我添加的最后一个功能是在未选择任何内容的情况下显示的默认值/附加项目,例如“请选择”。我可以通过 OnDataBind 事件中的属性 DefaultValueText 进行设置。

现在这是我面临的问题:

在InitializeDataCell中,如果我设置

box.AppendDataBoundItems = true;

并调用

box.DataBind();

下拉列表,则包含所有项目以及附加的默认项目。 它在 OnDataBind 事件中也能很好地工作,如果数据绑定项不包含值,我现在可以在其中选择默认值。

但是当下拉列表显示在网格视图中时,它包含默认值以及来自数据源两次的所有内容,因为我设置了 AppendDataBoundItems = true,这导致下拉列表在添加项目时不会清除其项目 gridview 必须调用 databind 两次,但它只在 OnDataBind 事件方法中注册一次。我只在那里看到一个调用,在那一刻,一切都很好,下拉列表包含默认项目以及数据源中的每个项目之一。

有什么建议可以在哪里或如何处理数据绑定,以便我可以完全控制数据绑定?

I managed to override the Boundfield to display a dropdownlist if I put it in a Gridview.

protected override void InitializeDataCell(DataControlFieldCell cell, DataControlRowState rowState)
    {
        Control child = null;
        Control cellControl = null;

        if ((((rowState & DataControlRowState.Edit) != DataControlRowState.Normal) && !this.ReadOnly) 
            || ((rowState & DataControlRowState.Insert) != DataControlRowState.Normal))
        {
            // If data cell is in edit mode, create DropDownList editor for this cell
            // and set data properties.
            
            DropDownList box = new DropDownList();                
            box.Items.Add(DefaultValueText);               

            box.DataSource = this.GetDataSource();
            box.DataMember = this.BusinessObjectName;
            box.DataTextField = this.DataTextField;
            box.DataValueField = this.DataValueField;
            box.AppendDataBoundItems = true;
            box.ToolTip = this.HeaderText;

            cell.Controls.Add(box);
            box.DataBind();
            // if in edit mode, prepare dropdown for binding
            if ((this.DataField.Length != 0) && ((rowState & DataControlRowState.Edit) != DataControlRowState.Normal))
            {
                cellControl = box;
            }
        }
        else if (this.DataField.Length != 0)    // if in read only mode, prepare cell for binding
        {
            cellControl = cell;
        }

        if ((cellControl != null) && base.Visible)
        {
            cellControl.DataBinding += new EventHandler(this.OnDataBindField);
        }
    }
    

    protected override void OnDataBindField(object sender, EventArgs e)
    {
        Control control = (Control)sender;
        Control namingContainer = control.NamingContainer;
        object dataValue = this.GetValue(namingContainer);
        bool encode = (this.SupportsHtmlEncode && this.HtmlEncode) && (control is TableCell);
        string str = this.FormatDataValue(dataValue, encode);
        if (control is TableCell)
        {
            if (str.Length == 0)
            {
                str = " ";
            }
            ((TableCell)control).Text = str;
        }
        else
        {
            //If data cell is in edit mode, set selected value of DropDownList 
            if (dataValue != null)
            {
                DropDownList dropDownList = (DropDownList) control;
                
                ListItem itm = dropDownList.Items.FindByText(dataValue.ToString());
                if (itm != null)
                {
                    dropDownList.Text = itm.Value;
                }
                else
                    ((DropDownList)control).Text = DefaultValueText;
            }
        }
    }

The last feature I added is a default value/ additional item to display if nothing has been selected, like "please select" for example. I can set this through the property DefaultValueText in the OnDataBind event.

Now here's the problem I am facing:

In InitializeDataCell, if I set

box.AppendDataBoundItems = true;

and call

box.DataBind();

The dropdownlist has all the items plus the additional default item.
It also works nicely in the OnDataBind event, where I can now select the default if the databound item does not contain a value.

But when the dropdownlist is displayed in the gridview, it contains the default value plus everything from the datasource TWICE, because I set AppendDataBoundItems = true, which leads the dropdown to NOT clear it's items when items are added
The gridview must be calling databind twice, but it's only registering once in the OnDataBind event method. I only see one call there, and in that moment, everything is fine, the dropdown contains the default item plus one of each item from the datasource.

Any suggestions where or how I can handle the databinding so that I have full control over the databinding?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

归途 2024-08-23 12:03:41

我设法让它工作

我将用于设置 selectedValue 的所有代码移至 DropDownList 的 DataBound 事件。在这种情况下,数据绑定已经发生,并且值列表可供我设置 selectedValue。我自己不再调用 DataBind,因为无论如何它都会在控件上被调用。我只在开头添加“进行选择”项并将 AppendDataBoundItems 设置为 true。

现在在某些只读状态下可能会出现未处理的情况,因为我不处理任何 Cell.Databinding() 事件。

感兴趣的人可以查看完整的源代码...

它基于 Javad Zarrinabadi 的示例,位于 CodeProjct

用法:

DropDownBoundField dropDownBoundField = new DropDownBoundField();
        dropDownBoundField.HeaderText = "NyColumnName";
        dropDownBoundField.BusinessObjectName = "BusinessLogic.MyDataClass";
        dropDownBoundField.SelectMethod = "GetEnumerable";
        dropDownBoundField.DataTextField = "Name";   // what should be displayed
        dropDownBoundField.DataValueField = "Id";    // value behind the displayed text
        dropDownBoundField.DataField = "IdProperty"; // Property to bind to
        dropDownBoundField.DefaultValueText = "Select";  // text on first item as 
                                                      default if DataField is null            
        dropDownBoundField.FindBy = SetSelectedValueBy.Value  // Choose how the DataField is being evaluated, as source for the value or the text
        GridView.Columns.Add(dropDownBoundField);

类:

 using System;
 using System.Web.UI.WebControls;
 using System.Web.UI;
 using System.ComponentModel;
 using System.Web;
 using System.Collections.Specialized;

namespace IDVCode.GridViews
{
public class DropDownField : BoundField
{
    #region fields
    private string _listDataSourceID;
    private string _listDataMember;
    private string _listDataTextField;
    private string _listDataValueField;
    #endregion 

    #region eventHandler

    protected override void InitializeDataCell(DataControlFieldCell cell, DataControlRowState rowState)
    {
            DropDownList dropDownList = new DropDownList();
            dropDownList.ToolTip = HeaderText;
            dropDownList.DataSourceID = ListDataSourceID;
            dropDownList.DataMember = ListDataMember;
            dropDownList.DataTextField = ListDataTextField;
            dropDownList.DataValueField = ListDataValueField;
            dropDownList.Enabled = !ReadOnly;
            cell.Controls.Add(dropDownList);

            if (rowState == DataControlRowState.Normal || rowState == DataControlRowState.Alternate || ReadOnly)
            {
                dropDownList.Enabled = false;
            }
            if (DataField.Length != 0) // && ((rowState & DataControlRowState.Edit) != DataControlRowState.Normal))
            {
                dropDownList.DataBound += new EventHandler(OnDataBindField);
            }
       }

    protected override void OnDataBindField(object sender, EventArgs e)
    {
        Control control = (Control)sender;
        Control namingContainer = control.NamingContainer;
        object dataValue = GetValue(namingContainer);
        bool encode = (SupportsHtmlEncode && HtmlEncode) && (control is TableCell);
        string str = FormatDataValue(dataValue, encode);
        if (control is TableCell)
        {
            if (str.Length == 0)
            {
                str = " ";
            }
            ((TableCell)control).Text = str;
        }
        else
        {
            if (!(control is DropDownList))
            {
                throw new HttpException("BoundField_WrongControlType");
            }
            if (((DropDownList)control).Items.Count > 0)    // Don't call selectedValue if empty
            {
                if (dataValue != null)
                {
                    DropDownList dropDownList = (DropDownList)control;

                    ListItem item = null;
                    if (FindBy == SetSelectedValueBy.Value)
                    {
                        item = dropDownList.Items.FindByValue(dataValue.ToString());
                    }
                    else
                    {
                        item = dropDownList.Items.FindByText(dataValue.ToString());
                    }

                    if (item != null)
                        dropDownList.Text = item.Value;
                    else
                    {
                        ListItem defaultItem = dropDownList.Items.FindByText(DefaultValueText);
                        if (defaultItem != null)
                            dropDownList.SelectedValue = defaultItem.Value;
                    }
                }
            }
        }
    }

    public override void ExtractValuesFromCell(IOrderedDictionary dictionary, DataControlFieldCell cell,
        DataControlRowState rowState, bool includeReadOnly)
    {
        Control control = null;
        string dataField = DataField;
        object text = null;
        string nullDisplayText = NullDisplayText;
        if (((rowState & DataControlRowState.Insert) == DataControlRowState.Normal) || InsertVisible)
        {
            if (cell.Controls.Count > 0)
            {
                control = cell.Controls[0];
                DropDownList box = control as DropDownList;
                if (box != null)
                {
                    text = box.SelectedValue;
                }
            }
            else if (includeReadOnly)
            {
                string s = cell.Text;
                if (s == " ")
                {
                    text = string.Empty;
                }
                else if (SupportsHtmlEncode && HtmlEncode)
                {
                    text = HttpUtility.HtmlDecode(s);
                }
                else
                {
                    text = s;
                }
            }
            if (text != null)
            {
                if (((text is string) && (((string)text).Length == 0)) && ConvertEmptyStringToNull)
                {
                    text = null;
                }
                if (((text is string) && (((string)text) == nullDisplayText)) && (nullDisplayText.Length > 0))
                {
                    text = null;
                }
                if (dictionary.Contains(dataField))
                {
                    dictionary[dataField] = text;
                }
                else
                {
                    dictionary.Add(dataField, text);
                }
            }
        }
    }

    #endregion

    #region Properties

    public virtual string ListDataSourceID
    {
        get
        {
            if (_listDataSourceID == null)
            {
                object stateBag = ViewState["ListDataSourceID"];
                if (stateBag != null)
                {
                    _listDataSourceID = (string)stateBag;
                }
                else
                {
                    _listDataSourceID = string.Empty;
                }
            }
            return _listDataSourceID;
        }
        set
        {
            if (!object.Equals(value, ViewState["ListDataSourceID"]))
            {
                ViewState["ListDataSourceID"] = value;
                _listDataSourceID = value;
                OnFieldChanged();
            }
        }
    }

    public virtual string ListDataMember
    {
        get
        {
            if (_listDataMember == null)
            {
                object stateBag = ViewState["ListDataMember"];
                if (stateBag != null)
                {
                    _listDataMember = (string)stateBag;
                }
                else
                {
                    _listDataMember = string.Empty;
                }
            }
            return _listDataMember;
        }
        set
        {
            if (!object.Equals(value, ViewState["ListDataMember"]))
            {
                ViewState["ListDataMember"] = value;
                _listDataMember = value;
                OnFieldChanged();
            }
        }
    }

    public virtual string ListDataTextField
    {
        get
        {
            if (_listDataTextField == null)
            {
                object stateBag = ViewState["ListDataTextField"];
                if (stateBag != null)
                {
                    _listDataTextField = (string)stateBag;
                }
                else
                {
                    _listDataTextField = string.Empty;
                }
            }
            return _listDataTextField;
        }
        set
        {
            if (!object.Equals(value, ViewState["ListDataTextField"]))
            {
                ViewState["ListDataTextField"] = value;
                _listDataTextField = value;
                OnFieldChanged();
            }
        }
    }

    public virtual string ListDataValueField
    {
        get
        {
            if (_listDataValueField == null)
            {
                object stateBag = ViewState["ListDataValueField"];
                if (stateBag != null)
                {
                    _listDataValueField = (string)stateBag;
                }
                else
                {
                    _listDataValueField = string.Empty;
                }
            }
            return _listDataValueField;
        }
        set
        {
            if (!object.Equals(value, ViewState["ListDataValueField"]))
            {
                ViewState["ListDataValueField"] = value;
                _listDataValueField = value;
                OnFieldChanged();
            }
        }
    }

    [Description("Sets a default value if applicable")]
    [Category("Appearance")]
    public string DefaultValueText
    {
        get
        {
            object val = ViewState["DefaultValueText"];
            if (val != null)
            {
                return (string)val;
            }
            return (string.Empty);
        }

        set
        {
            ViewState["DefaultValueText"] = value;
        }
    }

    [Description("Defines how the SelectedValue is set")]
    [Category("Data")]
    [DefaultValue(SetSelectedValueBy.Value)]
    public SetSelectedValueBy FindBy
    {
        get
        {
            object val = ViewState["SetSelectedValueBy"];
            return val != null ? (SetSelectedValueBy) val : SetSelectedValueBy.Value;
        }
        set
        {
            ViewState["SetSelectedValueBy"] = value;
        }
    }

    public enum SetSelectedValueBy
    {
        Text,
        Value
    }

    #endregion
}

}

I managed to get it working

I moved all the code for setting the selectedValue to the DataBound event of the DropDownList. In this event, the databinding already happened and the list of values is available for me to set the selectedValue. I don't call DataBind myself anymore, since it's being called anyway on the control. I only add the "make a selection" item at the beginning and set AppendDataBoundItems to true.

There might be unhandled situations now in certain read only states, because I don't handle any Cell.Databinding() events.

Complete sourcecode for those who are interested...

It's based on the example from Javad Zarrinabadi at CodeProjct

usage:

DropDownBoundField dropDownBoundField = new DropDownBoundField();
        dropDownBoundField.HeaderText = "NyColumnName";
        dropDownBoundField.BusinessObjectName = "BusinessLogic.MyDataClass";
        dropDownBoundField.SelectMethod = "GetEnumerable";
        dropDownBoundField.DataTextField = "Name";   // what should be displayed
        dropDownBoundField.DataValueField = "Id";    // value behind the displayed text
        dropDownBoundField.DataField = "IdProperty"; // Property to bind to
        dropDownBoundField.DefaultValueText = "Select";  // text on first item as 
                                                      default if DataField is null            
        dropDownBoundField.FindBy = SetSelectedValueBy.Value  // Choose how the DataField is being evaluated, as source for the value or the text
        GridView.Columns.Add(dropDownBoundField);

Class:

 using System;
 using System.Web.UI.WebControls;
 using System.Web.UI;
 using System.ComponentModel;
 using System.Web;
 using System.Collections.Specialized;

namespace IDVCode.GridViews
{
public class DropDownField : BoundField
{
    #region fields
    private string _listDataSourceID;
    private string _listDataMember;
    private string _listDataTextField;
    private string _listDataValueField;
    #endregion 

    #region eventHandler

    protected override void InitializeDataCell(DataControlFieldCell cell, DataControlRowState rowState)
    {
            DropDownList dropDownList = new DropDownList();
            dropDownList.ToolTip = HeaderText;
            dropDownList.DataSourceID = ListDataSourceID;
            dropDownList.DataMember = ListDataMember;
            dropDownList.DataTextField = ListDataTextField;
            dropDownList.DataValueField = ListDataValueField;
            dropDownList.Enabled = !ReadOnly;
            cell.Controls.Add(dropDownList);

            if (rowState == DataControlRowState.Normal || rowState == DataControlRowState.Alternate || ReadOnly)
            {
                dropDownList.Enabled = false;
            }
            if (DataField.Length != 0) // && ((rowState & DataControlRowState.Edit) != DataControlRowState.Normal))
            {
                dropDownList.DataBound += new EventHandler(OnDataBindField);
            }
       }

    protected override void OnDataBindField(object sender, EventArgs e)
    {
        Control control = (Control)sender;
        Control namingContainer = control.NamingContainer;
        object dataValue = GetValue(namingContainer);
        bool encode = (SupportsHtmlEncode && HtmlEncode) && (control is TableCell);
        string str = FormatDataValue(dataValue, encode);
        if (control is TableCell)
        {
            if (str.Length == 0)
            {
                str = " ";
            }
            ((TableCell)control).Text = str;
        }
        else
        {
            if (!(control is DropDownList))
            {
                throw new HttpException("BoundField_WrongControlType");
            }
            if (((DropDownList)control).Items.Count > 0)    // Don't call selectedValue if empty
            {
                if (dataValue != null)
                {
                    DropDownList dropDownList = (DropDownList)control;

                    ListItem item = null;
                    if (FindBy == SetSelectedValueBy.Value)
                    {
                        item = dropDownList.Items.FindByValue(dataValue.ToString());
                    }
                    else
                    {
                        item = dropDownList.Items.FindByText(dataValue.ToString());
                    }

                    if (item != null)
                        dropDownList.Text = item.Value;
                    else
                    {
                        ListItem defaultItem = dropDownList.Items.FindByText(DefaultValueText);
                        if (defaultItem != null)
                            dropDownList.SelectedValue = defaultItem.Value;
                    }
                }
            }
        }
    }

    public override void ExtractValuesFromCell(IOrderedDictionary dictionary, DataControlFieldCell cell,
        DataControlRowState rowState, bool includeReadOnly)
    {
        Control control = null;
        string dataField = DataField;
        object text = null;
        string nullDisplayText = NullDisplayText;
        if (((rowState & DataControlRowState.Insert) == DataControlRowState.Normal) || InsertVisible)
        {
            if (cell.Controls.Count > 0)
            {
                control = cell.Controls[0];
                DropDownList box = control as DropDownList;
                if (box != null)
                {
                    text = box.SelectedValue;
                }
            }
            else if (includeReadOnly)
            {
                string s = cell.Text;
                if (s == " ")
                {
                    text = string.Empty;
                }
                else if (SupportsHtmlEncode && HtmlEncode)
                {
                    text = HttpUtility.HtmlDecode(s);
                }
                else
                {
                    text = s;
                }
            }
            if (text != null)
            {
                if (((text is string) && (((string)text).Length == 0)) && ConvertEmptyStringToNull)
                {
                    text = null;
                }
                if (((text is string) && (((string)text) == nullDisplayText)) && (nullDisplayText.Length > 0))
                {
                    text = null;
                }
                if (dictionary.Contains(dataField))
                {
                    dictionary[dataField] = text;
                }
                else
                {
                    dictionary.Add(dataField, text);
                }
            }
        }
    }

    #endregion

    #region Properties

    public virtual string ListDataSourceID
    {
        get
        {
            if (_listDataSourceID == null)
            {
                object stateBag = ViewState["ListDataSourceID"];
                if (stateBag != null)
                {
                    _listDataSourceID = (string)stateBag;
                }
                else
                {
                    _listDataSourceID = string.Empty;
                }
            }
            return _listDataSourceID;
        }
        set
        {
            if (!object.Equals(value, ViewState["ListDataSourceID"]))
            {
                ViewState["ListDataSourceID"] = value;
                _listDataSourceID = value;
                OnFieldChanged();
            }
        }
    }

    public virtual string ListDataMember
    {
        get
        {
            if (_listDataMember == null)
            {
                object stateBag = ViewState["ListDataMember"];
                if (stateBag != null)
                {
                    _listDataMember = (string)stateBag;
                }
                else
                {
                    _listDataMember = string.Empty;
                }
            }
            return _listDataMember;
        }
        set
        {
            if (!object.Equals(value, ViewState["ListDataMember"]))
            {
                ViewState["ListDataMember"] = value;
                _listDataMember = value;
                OnFieldChanged();
            }
        }
    }

    public virtual string ListDataTextField
    {
        get
        {
            if (_listDataTextField == null)
            {
                object stateBag = ViewState["ListDataTextField"];
                if (stateBag != null)
                {
                    _listDataTextField = (string)stateBag;
                }
                else
                {
                    _listDataTextField = string.Empty;
                }
            }
            return _listDataTextField;
        }
        set
        {
            if (!object.Equals(value, ViewState["ListDataTextField"]))
            {
                ViewState["ListDataTextField"] = value;
                _listDataTextField = value;
                OnFieldChanged();
            }
        }
    }

    public virtual string ListDataValueField
    {
        get
        {
            if (_listDataValueField == null)
            {
                object stateBag = ViewState["ListDataValueField"];
                if (stateBag != null)
                {
                    _listDataValueField = (string)stateBag;
                }
                else
                {
                    _listDataValueField = string.Empty;
                }
            }
            return _listDataValueField;
        }
        set
        {
            if (!object.Equals(value, ViewState["ListDataValueField"]))
            {
                ViewState["ListDataValueField"] = value;
                _listDataValueField = value;
                OnFieldChanged();
            }
        }
    }

    [Description("Sets a default value if applicable")]
    [Category("Appearance")]
    public string DefaultValueText
    {
        get
        {
            object val = ViewState["DefaultValueText"];
            if (val != null)
            {
                return (string)val;
            }
            return (string.Empty);
        }

        set
        {
            ViewState["DefaultValueText"] = value;
        }
    }

    [Description("Defines how the SelectedValue is set")]
    [Category("Data")]
    [DefaultValue(SetSelectedValueBy.Value)]
    public SetSelectedValueBy FindBy
    {
        get
        {
            object val = ViewState["SetSelectedValueBy"];
            return val != null ? (SetSelectedValueBy) val : SetSelectedValueBy.Value;
        }
        set
        {
            ViewState["SetSelectedValueBy"] = value;
        }
    }

    public enum SetSelectedValueBy
    {
        Text,
        Value
    }

    #endregion
}

}

给妤﹃绝世温柔 2024-08-23 12:03:41

好吧,我知道在某些情况下它确实会绑定多次(在更改条件等时),因此您必须再次处理此问题......您可以清除列表并重新绑定吗?

Well, I know in some situations it does bind multiple times (upon changing criteria, etc.) so you are bound to deal with this issue again... can you clear the list and rebind?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文