Как я могу программно добавить триггеры в ASP.NET UpdatePanel?

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

У меня нет проблем с добавлением элементов управления DropDownList в мою панель UpdatePanel, но я не могу связать события.

После загрузки страницы раскрывающиеся списки со своими данными есть, но их изменение не вызывает ни обработчик события SelectedIndexChanged, ни обновление QuoteUpdatePanel. У меня есть что-то вроде этого:

Изменить: Поскольку программно добавлено Элементы управления AsyncPostBackTrigger не поддерживаются, я изменил свой код на это, но все равно не получаю событие:

Редактировать 2: Попытался добавить PlaceHolder для добавления раскрывающихся списков (вместо этого непосредственно в ContentTemplateContainer, по-прежнему никаких событий не происходит.

QuotePanel.ASCX

<asp:ScriptManager ID="ScriptManager" runat="server" />

<asp:UpdatePanel ID="QuoteUpdatePanel" runat="server" ChildrenAsTriggers="true">
    <ContentTemplate>
        Cost: <asp:Label ID="QuoteCostLabel" runat="server" />
        <fieldset id="standard-options">
            <legend>Standard Options</legend>
            <asp:UpdatePanel ID="StandardOptionsUpdatePanel" runat="server" ChildrenAsTriggers="true" UpdateMode="Conditional">
                <ContentTemplate>
                <asp:PlaceHolder ID="StandardOptionsPlaceHolder" runat="server" />                   
                </ContentTemplate>
            </asp:UpdatePanel>
        </fieldset>
    </ContentTemplate>
</asp:UpdatePanel>

Код для добавления раскрывающихся списков и события, для которого они должны быть подключены:

protected void PopluateUpdatePanel(IEnumerable<IQuoteProperty> standardOptions)
{
    foreach (IQuoteProperty standardOp in standardOptions)
    {
        QuotePropertyDropDownList<IQuoteProperty> dropDownList = new QuotePropertyDropDownList<IQuoteProperty>(standardOp);
        dropDownList.SelectedIndexChanged += QuotePropertyDropDown_SelectedIndexChanged;
        dropDownList.ID = standardOp.GetType().Name + "DropDownList";
        dropDownList.CssClass = "quote-property-dropdownlist";

        Label propertyLabel = new Label() {Text = standardOp.Title, CssClass = "quote-property-label"};

        StandardOptionsPlaceHolder.Controls.Add(propertyLabel);
        StandardOptionsPlaceHolder.Controls.Add(dropDownList);

        _standardOptionsDropDownLists.Add(dropDownList);

        ScriptManager.RegisterAsyncPostBackControl(dropDownList);

    }

}

void QuotePropertyDropDown_SelectedIndexChanged(object sender, EventArgs e)
{
    QuoteCostLabel.Text = QuoteCost.ToString();
    StandardOptionsUpdatePanel.Update();
}

person scottm    schedule 26.04.2010    source источник


Ответы (1)


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

Обходной путь заключается в том, чтобы добавить их в событие Page_Init и установить для свойства ControlID триггера значение уникального идентификатора элемента управления:

AsyncPostBackTrigger trigger = new AsyncPostBackTrigger();
// unique id instead of client id
trigger.ControlID = yourDropDownControl.UniqueID;  
trigger.EventName = "SelectedIndexChanged"; 
QuoteUpdatePanel.Triggers.Add(trigger);

Кажется, это сработало. Я создал аналогичную структуру страницы/элемента управления выше. Таким образом, есть пользовательский элемент управления QuotePropertyControl и страница Default, которая содержит этот элемент управления.

Я добавил свойство dropDownList.AutoPostBack = true и смог поймать асинхронную обратную передачу из раскрывающегося списка. Итак, предположил, что проблема была в этом свойстве.

Еще одна вещь: на самом деле не имеет значения, как зарегистрировать асинхронный триггер; оба варианта ScriptManager.RegisterAsyncPostBackControl и через AsyncPostBackTrigger работали как часы (до момента инициализации страницы).

Вот как я это сделал:

QuotePropertyControl.ascx.cs

private string[] data = { "a", "b", "c", "d", "e" };

public void PopluateUpdatePanel(IEnumerable<string> standardOptions)
{
    foreach (string standardOp in standardOptions)
    {
        DropDownList dropDownList = new DropDownList();
        dropDownList.SelectedIndexChanged +=
            QuotePropertyDropDown_SelectedIndexChanged;
        dropDownList.ID = standardOp + "DropDownList";
        dropDownList.CssClass = "quote-property-dropdownlist";
        dropDownList.AutoPostBack = true;
        dropDownList.DataSource = data;
        dropDownList.DataBind();

        Label propertyLabel = new Label() { Text = standardOp };

        StandardOptionsPlaceHolder.Controls.Add(propertyLabel);
        StandardOptionsPlaceHolder.Controls.Add(dropDownList);

        ScriptManager.GetCurrent(Page)
            .RegisterAsyncPostBackControl(dropDownList);
    }
}

protected void QuotePropertyDropDown_SelectedIndexChanged(
    object sender,
    EventArgs e
    )
{
    StandardOptionsUpdatePanel.Update();
}

QuotePropertyControl.ascx

<asp:UpdatePanel ID="QuoteUpdatePanel" runat="server" ChildrenAsTriggers="true">
    <ContentTemplate>
        Cost:
        <asp:Label ID="QuoteCostLabel" runat="server" />
        <fieldset id="standard-options">
            <legend>Standard Options</legend>
            <asp:UpdatePanel ID="StandardOptionsUpdatePanel" 
                runat="server" 
                ChildrenAsTriggers="true" 
                UpdateMode="Conditional">
                <ContentTemplate>
                    <asp:PlaceHolder ID="StandardOptionsPlaceHolder" 
                    runat="server" />
                </ContentTemplate>
            </asp:UpdatePanel>
        </fieldset>
    </ContentTemplate>
</asp:UpdatePanel>

Default.aspx.cs

string[] names = { "ab", "bc", "ef" };

protected void Page_Init(object sender, EventArgs e)
{
    ctlQuoteProperty.PopluateUpdatePanel(names);
}

Default.aspx

<%@ Register Src="~/QuotePropertyControl.ascx" 
             TagPrefix="uc" 
             TagName="QuoteProperty" %>

<form id="form1" runat="server">
<div>
    <asp:ScriptManager ID="ScriptManager" runat="server" />
    <uc:QuoteProperty runat="server"
        ID="ctlQuoteProperty">
    </uc:QuoteProperty>
</div>
</form>
person Alex    schedule 27.04.2010
comment
Это отдельный пользовательский элемент управления. В текущей реализации я добавил триггеры в событие QuotePanelControl_Init(). После вашего предложения я сделал метод PopulateUpdatePanel общедоступным и вызвал его из события Init страницы. Я все еще не получаю никаких событий. - person scottm; 27.04.2010
comment
@scottm: я попробую на своей стороне и сообщу о прогрессе - person Alex; 28.04.2010
comment
Любая идея, почему я могу поддерживать состояние просмотра раскрывающегося списка? Он продолжает возвращаться к умолчанию - person scottm; 28.04.2010
comment
Не могли бы вы объяснить проблему более подробно? Кажется, состояние просмотра загружается нормально. - person Alex; 28.04.2010
comment
@Alex, когда я изменяю один из сгенерированных раскрывающихся списков, после того как он обновляет стоимость, похоже, что элементы управления добавляются снова (в QuotePanel_Init), и поэтому значение сбрасывается до значения по умолчанию. - person scottm; 28.04.2010
comment
@scottm, элементы управления следует добавлять с каждым событием Page_Init (или около того), потому что после этого состояние просмотра загружается в элементы управления. Поэтому важно добавить те же элементы управления (с теми же идентификаторами), которые были добавлены до того, как произошла обратная передача. Если элементы управления не меняются (как в примере, который я предоставил в своем ответе: 3 выпадающих списка, те же данные, те же идентификаторы - после обратной отправки), состояние просмотра должно быть загружено в элементы управления. Попробуйте пример выше, даже после обратной передачи выбранное значение не будет сброшено до значения по умолчанию. - person Alex; 28.04.2010