Telerik RadListView внутри панели обновления asp.net не обновляется
Последние пару дней я бился головой об стену, пытаясь заставить этот сценарий сработать.
у меня есть <asp:UpdatePanel>
на странице, которая имеет внешний триггер и содержит Telerik RadListView
:
<asp:UpdatePanel runat="server" ID="RationUpdatePanel" UpdateMode="Conditional" ChildrenAsTriggers="true">
<ContentTemplate>
<telerik:RadListView ID="RationListView runat="server"
DataSourceId="RationDataSource"
OnItemCanceling="ItemCancelingHandler"
OnItemEditing="ItemEditingHandler"
OnItemUpdating="ItemUpdateHandler">
<LayoutTemplate>
<table>
<thead>
<tr>...</tr>
</thead>
<tbody>
<tr id="itemPlaceHolder" runat="server"/>
</tbody>
</table>
</LayoutTemplate>
<ItemTemplate>
<tr>
<td>
<asp:LinkButton ID="EditButton" runat="server" CausesValidation="False" CommandName="Edit" Text="Edit" ToolTip="Edit" />
<asp:LinkButton ID="DeleteButton" runat="server" CausesValidation="False" CommandName="Delete" Text="Delete" ToolTip="Delete" />
</td>
<td>...</td>
</tr>
</ItemTemplate>
<EditItemTemplate>
<tr>
<td>
<asp:LinkButton ID="SaveButton" runat="server" CausesValidation="False" CommandName="Save" Text="Save" ToolTip="Save" />
<asp:LinkButton ID="CancelButton" runat="server" CausesValidation="False" CommandName="Cancel" Text="Cancel" ToolTip="Update" />
</td>
<td>...</td>
</tr>
</EditItemTemplate>
</telerik:RadListView>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="UseRationButton" EventName="Click" />
</Triggers>
</UpdatePanel>
Код позади выглядит так:
protected void RationListView_ItemEditing(object sender, RadListViewCommandEventArgs e)
{
((RadListViewDataItem)e.ListViewItem).Edit = true;
}
protected void RationListView_ItemCanceling(object sender, RadListViewCommandEventArgs e)
{
RationListView.ClearEditItems();
((RadListViewDataItem)e.ListViewItem).Edit = false;
}
Нажав на EditButton
или же CancelButton
произвел ожидаемые события и вызывается подпрограмма ObjectDataSource для перепривязки списка, но панель обновления не обновляется. призвание RationUpdatePanel.Update()
От обработчиков событий ситуация не меняется. Код работает правильно за пределами панели обновления: режим меняется, и отображаются кнопки из другого шаблона.
В любом случае нажатие на внешний триггер приводит к отображению списка.
Обновление: я добавил пару обратных вызовов javascript к классу PageManager в браузере для beginRequest и endRequest. Они просто отображают предупреждение, когда происходит событие.
Страница содержит несколько элементов, которые в основном выглядят так (детали опущены):
<div>
<div>
<asp:DropDownList ID="RationDdl"/>
<asp:Button ID="UseRationButton"/>
</div>
<div>
<asp:DropDownList ID="AnimalGroupDdl"/>
<asp:UpdatePanel ID="AnimalWeightUpdatePanel"/>
<ContentTemplate>
<asp:DropDownList ID="AnimalWeightDdl"/>
</ContentTemplate>
</asp:UpdatePanel>
</div>
</div>
<div>
<telerik:RadListBox>
</telerik:RadListBox>
</div>
<div>
<asp:UpdatePanel ID="FeedPreviewUpdatePanel">
<ContentTemplate>
<asp:Repeater>
</asp:Repeater>
</ContentPanel>
</asp:UpdatePanel>
</div>
<div>
<!-- this contains the update panel shown above -->
</div>
UseFeedRationButton
в первом div это внешний триггер для RationUpdatePanel
, AnimalGroupDdl
является внешним триггером для AnimalWeightUpdatePanel
, Обработчик события SelectedIndexChanged на AnimalGroupDdl
заполняет AnimalWeightDdl
с доступными весовыми категориями для выбранной группы. Не имеет никакого взаимодействия с RationUpdatePanel
или же FeedPreviewUpdatePanel
,
Вот разметка для UseRationButton
:
<asp:Button ID="UseRationButton" runat="server"
Text="Use This Ration"
OnClick="UseRationButton_Click"
CausesValidation="true"
ValidationGroup="UseRation"
UseSubmitBehavior="false">
</asp:Button>
И вот код позади:
protected void UseRationButton_Click(object sender, EventArgs e)
{
string text = this.RationDdl.SelectedItem.Text;
this.RationNameLabel.Text = text;
this.RationDataSource.SelectParameters["RationId"].DefaultValue = this.RationDdl.SelectedValue;
}
Есть два сценария, которые я тестировал:
1) Выберите рацион из RationDdl
и нажмите UseRationButton
2) Выберите группу животных и выполните сценарий 1.
В сценарии 1 асинхронная обратная передача инициируется клиентским кодом asp.net, а событие кнопки обрабатывается на стороне сервера. RationListView заполнен, но код endRequest на стороне клиента никогда не выполняется (предупреждение не отображается). Последующие щелчки на элементах управления в RadListView вызывают асинхронную обратную передачу, но состояние списка не изменяется, и код endRequest на стороне клиента не выполняется.
В сценарии 2 инициируется асинхронная обратная передача, событие обрабатывается на стороне сервера и AnimalWeightDdl
населён. В этом случае выполняется код endRequest на стороне клиента (отображается предупреждение IS). После этого выбор нормы и нажатие на кнопку использования порции инициирует обратную передачу, заполняется представление списка и выполняется код endRequest. В этот момент нажатие на кнопки в представлении списка приводит к инициированию асинхронной обратной передачи, изменению состояния списка и выполнению кода endRequest.
Моя рабочая теория заключается в том, что что-то приводит к тому, что состояние класса диспетчера запросов страниц на клиенте становится неопределенным, но я не могу понять, что может быть причиной этого.
2 ответа
Исследование, которое я провел поздно вечером в пятницу и субботу, дало ответ на этот вопрос.
У меня был некоторый код, прикрепленный к Sys.WebForms.PageRequestManager
Событие endRequest, которое обновило текстовое поле, которое содержало временный заголовок для нового рациона. Код выглядел так:
///
/// reregister the change handlers after reloading the animal weight ddl and create a
/// temporary name for the ration based on animal choice and weight.
///
function animalWeightDdlOnLoad() {
var ddl = document.getElementById("<%= AnimalWeightDdl.ClientID %>");
//
// add event handler in a browser agnostic fashion
//
if (ddl.addEventListener) {
ddl.addEventListener("change", animalWeightDdlOnChange);
}
else if (ddl.attachEvent) {
ddl.attachEvent("onchange", animalWeightDdlOnChange);
}
else {
ddl.onchange = animalWeightDdlOnChange;
}
animalWeightDdlOnChange();
}
animalWeightDdlOnChange()
Ссылка на список параметров веса животных ddl:
///
/// create a temporary name for the ration
///
function animalWeightDdlOnChange() {
var ddl1 = document.getElementById("<%= AnimalGroupDdl.ClientID %>");
var ddl2 = document.getElementById("<%= AnimalWeightDdl.ClientID %>");
var text = document.getElementById("<%= RationNameText.ClientID %>");
text.value = ddl1.options[ddl1.selectedIndex].text + ' ' + ddl2.options[ddl2.selectedIndex].text + ' - Copy';
}
Однако, если список еще не был заполнен, ссылка на опции вызвала ошибку, которая остановила обработку endRequest. Вместо того чтобы запускать этот код при каждом асинхронном запросе, я изменил его на обработчик события change в группе животных ddl, например:
function animalGroupDdlOnSelectedChanged() {
//
// add a handler for the endRequest event which will be triggered by
// fetching the contents of the weight ddl.
//
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(animalWeightDdlOnLoad);
}
Затем в animalWeightDdlOnLoad()
Я добавил строку, чтобы удалить обработчик после выполнения запроса. Это гарантировало, что обработчик изменений для веса ddl будет работать только после заполнения списка. Задача решена. Но на всякий случай я добавил проверку длины списка опций ddl для веса животных.
Так что даже на первый взгляд невинный JavaScript может испортить обработку вашего асинхронного запроса в браузере.
Во-первых, если вы используете Telerik Rad Control, я предлагаю вам изменить asp:button
в telerik:RadButton
,
Вот пример
<telerik:RadButton ID="v" runat="server" Text="Use This Ration"
AutoPostBack="true"
ValidationGroup="UseRation" OnClick="UseRationButton_Click">
</telerik:RadButton>
protected void UseRationButton_Click(object sender, EventArgs e)
{
string text = this.RationDdl.SelectedItem.Text;
this.RationNameLabel.Text = text;
this.RationDataSource.SelectParameters["RationId"].DefaultValue = this.RationDdl.SelectedValue;
}
Обратите внимание, что вы должны добавить AutoPostBack="true"
в вашем RadButton .
И эти ссылки, MSDN Reference1 и MSDN Reference2 покажут детали использования панели обновления.