ASP.NET Boundfield, переопределенный для поддержки раскрывающегося списка, отсутствует одна последняя функция

Мне удалось переопределить Boundfield для отображения раскрывающегося списка, если я поместил его в 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;
            }
        }
    }

Последняя функция, которую я добавил, - это значение по умолчанию / дополнительный элемент, отображаемый, если ничего не было выбрано, например, выберите, например. Я могу установить это с помощью свойства DefaultValueText в событии OnDataBind.

Вот проблема, с которой я столкнулся:

В InitializeDataCell, если я установил

box.AppendDataBoundItems = true;

и позвони

box.DataBind();

В раскрывающемся списке есть все элементы плюс дополнительный элемент по умолчанию. Он также прекрасно работает в событии OnDataBind, где теперь я могу выбрать значение по умолчанию, если элемент привязки данных не содержит значения.

Но когда раскрывающийся список отображается в представлении сетки, он содержит значение по умолчанию плюс все из источника данных ДВАЖДЫ, потому что я установил AppendDataBoundItems = true, что приводит к тому, что раскрывающийся список НЕ очищает его элементы при добавлении элементов gridview должен вызывать привязку данных дважды, но только один раз регистрируется в методе события OnDataBind. Я вижу там только один вызов, и в этот момент все в порядке, раскрывающийся список содержит элемент по умолчанию плюс один из каждого элемента из источника данных.

Любые предложения, где и как я могу обрабатывать привязку данных, чтобы иметь полный контроль над привязкой данных?


person Niels Ziegler    schedule 30.12.2009    source источник


Ответы (2)


Мне удалось заставить его работать

Я переместил весь код для установки selectedValue в событие DataBound DropDownList. В этом случае привязка данных уже произошла, и мне доступен список значений для установки selectedValue. Сам я больше не вызываю DataBind, так как он все равно вызывается в элементе управления. Я только добавляю элемент «сделать выбор» в начале и устанавливаю для AppendDataBoundItems значение true.

В некоторых состояниях только для чтения могут возникнуть необработанные ситуации, потому что я не обрабатываю никакие события Cell.Databinding ().

Полный исходный код для тех, кому интересно ...

Он основан на примере Джавада Зарринабади из 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
}

}

person Niels Ziegler    schedule 30.12.2009

Что ж, я знаю, что в некоторых ситуациях он привязывается несколько раз (при изменении критериев и т. Д.), Поэтому вы обязательно снова столкнетесь с этой проблемой ... вы можете очистить список и выполнить повторную привязку?

person Brian Mains    schedule 30.12.2009
comment
Единственный способ повлиять на привязку данных - это присоединить обработчик событий к DropDownList.DataBinding. И это вызывается только один раз (из того, что я вижу в режиме отладки), так кто копирует элементы во второй раз? Методы getModes (), связанные с раскрывающимся списком, получают количество совпадений, эквивалентное количеству имеющихся у меня строк (один раз для каждого инициализированного раскрывающегося списка). Может ли это исходить из состояния просмотра? Думаю, я могу попытаться выключить это, если возможно - person Niels Ziegler; 30.12.2009