Динамически добавленные DropDownlists не запускаются SelectedIndexChanged Event

Я многое видел по этой теме, но не могу найти решение. Я добавляю множество выпадающих списков с одним событием, но они не запускают SelectedIndexChanged evet. Вот код создателя drplist:

foreach (var row in cmdSelectCats.ExecuteReader())
{
    var id = row["ProductCategoryID"].ToString();

    var dropDownStatus = new DropDownList {ID = "DrpStatus-" + id};

    dropDownStatus.Items.Add(new ListItem("Aktif", "1"));
    dropDownStatus.Items.Add(new ListItem("Pasif", "2"));

    dropDownStatus.AutoPostBack = true; 
    dropDownStatus.SelectedIndexChanged += Status_SelectedIndexChanged;

    var tableCell = new TableCell();
    tableCell.Controls.Add(dropDownStatus);
    dropDownStatus.SelectedValue = row["ProductCategoryStatusID"].ToString();
    tableRow.Cells.Add(tableCell);
    TblCatList.Rows.Add(tableRow);
}

И, конечно же, мое событие:

public void Status_SelectedIndexChanged(object sender, EventArgs e)
{
    //DO SOMETHING
} 

Что мне не хватает?

3 ответа

Решение

Это общая проблема, связанная с жизненным циклом страницы:

Взгляните на следующие вопросы:

События кликов на массиве кнопок

Массив кнопок исчезает после нажатия кнопки

Динамически создать ImageButton

Теперь основные шаги, которые нужно помнить при создании динамических элементов управления:

  • Динамические элементы управления должны быть созданы в PreInit Если вы не работаете с главной страницей, создайте элементы управления в Init событие
  • Избегайте установки свойств, которые можно изменить в каждом сообщении в этих событиях, потому что при применении состояния просмотра (в событии поста) свойства будут переопределены
  • Динамические элементы управления должны создаваться при каждой публикации страницы, избегайте этого if(!this.IsPostBack) this.CreatemyDynamicControls();
  • Когда вы создаете элементы управления в PreInit или же Init события, их состояния будут автоматически установлены в пост-событии, что означает в LoadComplete Если ваши элементы управления будут содержать их состояние обратно, даже когда вы создадите их снова в каждом сообщении, и даже если вы явно не установили их состояние. Обратите внимание, что это поведение отличается, когда вы имеете дело с элементами управления, созданными во время разработки, в этом случае событие, в котором было установлено состояние, является событием Load
  • Подписка на событие должна произойти до PageLoadComplete или они не будут подняты

Рассмотрим следующее описание из MSDN

Если элементы управления создаются динамически во время выполнения или декларативно в шаблонах элементов управления с привязкой к данным, их события изначально не синхронизируются с событиями других элементов управления на странице. Например, для элемента управления, который добавляется во время выполнения, события Init и Load могут происходить намного позже в жизненном цикле страницы, чем те же события для элементов управления, созданных декларативно. Следовательно, с момента создания экземпляров динамически добавленные элементы управления и элементы управления в шаблонах повышают свои события один за другим, пока не обнаружат событие, во время которого они были добавлены в коллекцию элементов управления.

Вышесказанное мне не так понятно, но я обнаружил следующее. Следующие TextBoxсоздаются во время разработки

    protected void Page_PreInit(object sender, EventArgs e)
    {
        this.txtDesignTextBox1.Text = "From PreInit";
        this.txtDesignTextBox1.Text += DateTime.Now.ToString();
    }

    protected void Page_Init(object sender, EventArgs e)
    {
        this.txtDesignTextBox2.Text = "From Init";
        this.txtDesignTextBox2.Text += DateTime.Now.ToString();
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        this.txtDesignTextBox3.Text = "From Load";
        this.txtDesignTextBox3.Text += DateTime.Now.ToString();
    }

На первый взгляд вы можете подумать, что в каждом сообщении все текстовые поля обновляются с текущей датой, но это не так, поскольку они были созданы во время разработки и строго следуют жизненному циклу страницы ASP.Net, что означает их состояние. переопределяется после событий PreInit и Init, только txtDesignTextBox3 обновляется в каждом сообщении, потому что его Text свойство обновляется после установки состояния просмотраLoad событие).

Но с динамическими элементами управления поведение отличается, помните описание MSDN:

для элемента управления, добавляемого во время выполнения, события Init и Load могут происходить намного позже в жизненном цикле страницы.

Учтите следующее:

    protected void Page_PreInit(object sender, EventArgs e)
    {
        var textBox = new TextBox { Text = "From PreInit", Width = new Unit("100%") };
        textBox.Text += DateTime.Now.ToString();
        this.myPlaceHolder.Controls.Add(textBox);
    }

    protected void Page_Init(object sender, EventArgs e)
    {
        var textBox = new TextBox { Text = "From Init", Width = new Unit("100%") };
        textBox.Text += DateTime.Now.ToString();
        this.myPlaceHolder.Controls.Add(textBox);
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        var textBox = new TextBox { Text = "From Load", Width = new Unit("100%") };
        textBox.Text += DateTime.Now.ToString();
        this.myPlaceHolder.Controls.Add(textBox);
    }

В этом случае элементы управления ведут себя немного иначе, в этом случае в каждом сообщении элементы управления никогда не обновляются, даже элементы управления, созданные в Load событие

Причина в том, что их события жизненного цикла происходят намного позже в жизненном цикле страницы, что означает, что их состояние переопределяется даже после события Load.

Чтобы решить эту проблему, вы можете использовать LoadComplete событие, в этом случае вы можете изменить состояние динамических элементов управления:

    protected void Page_LoadComplete(object sender, EventArgs e)
    {
        var textBox = new TextBox { Text = "From LoadComplete", Width = new Unit("100%") };
        textBox.Text += DateTime.Now.ToString();
        this.myPlaceHolder.Controls.Add(textBox);
    }

В этом случае состояние будет обновляться в каждом посте.

Однако примите во внимание, что вы должны подписаться на события динамического управления, до LoadComplete событие или они не будут подняты.

... Я знаю, что ненавижу такое поведение, поэтому я люблю MVC

В качестве краткого справочного материала для элементов управления, созданных во время разработки: обратите внимание на LoadViewState метод вызывается после PreInit а также Init события, но до Load событие. Load Событие считается стабильным, поскольку в этом случае вы можете получить доступ к состоянию просмотра ваших элементов управления. Также обратите внимание, что RaisePostBackEvent метод представляет управляющее событие, которое вызвало пост обратно, это может быть, SelectedIndexChanged, Clickи т. д. это событие обрабатывается после Load событие

Для получения полной подробной спецификации прочитайте документацию по жизненному циклу страницы MSDN.

Я обычно видел это, вызванное проблемой жизненного цикла страницы. Если элемент управления создается только при возникновении события, то при срабатывании события с измененным индексом элемент управления не существует, чтобы связать его с обратной передачей.

Пример:

  1. MyEvent горит. Выпадающий создан. Указан обработчик событий.
  2. Индекс измененного события сработал. Страница перезагружается. Выпадающий не найден, не может стрелять.

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

Вам не хватает:
1- переопределить SaveViewState
2- Переопределить LoadViewState

Я предоставляю пример кода для этого вопроса. Я проверяю это. Это работает.

ASPX:

<form id="form1" runat="server">
<asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click" />
<div id="myDiv" runat="server">
</div>
<asp:Label ID="lblDescription" runat="server"></asp:Label>
</form>

Код позади:

public partial class Default : System.Web.UI.Page
    {
        private List<string> values = new List<string>();

        protected void Page_Load(object sender, EventArgs e)
        {

        }        

        protected override object SaveViewState()
        {
            object baseState = base.SaveViewState();            
            object[] allStates = new object[2];
            allStates[0] = baseState;
            allStates[1] = values;
            return allStates;
        }

        protected override void LoadViewState(object savedState)
        {
            object[] myState = (object[])savedState;
            if (myState[0] != null)
                base.LoadViewState(myState[0]);
            if (myState[1] != null)
            {
                values = (List<string>)myState[1];
                MyRender();
            }
        }

        protected void Button1_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < 10; i++)
            {
                DropDownList ddl = new DropDownList();
                ddl.ID = "ClientID" + i;

                ddl.Items.Add("Item 1");
                ddl.Items.Add("Item 2");
                ddl.AutoPostBack = true;                
                values.Add(ddl.SelectedValue);

                myDiv.Controls.Add(ddl);
            }
        }

        private void MyRender()
        {
            for (int i = 0; i < values.Count; i++)
            {
                DropDownList ddl = new DropDownList();
                ddl.ID = "ClientID" + i;

                ddl.Items.Add("Item 1");
                ddl.Items.Add("Item 2");
                ddl.AutoPostBack = true;
                ddl.SelectedIndexChanged += new EventHandler(ddl_SelectedIndexChanged);

                myDiv.Controls.Add(ddl);
            }
        }

        void ddl_SelectedIndexChanged(object sender, EventArgs e)
        {
            lblDescription.Text = ((DropDownList)sender).ID + ": Selected Index Changed";
        }
    }
Другие вопросы по тегам