UpdatePanel、中继器、数据绑定问题
在用户控件中,我在 UpdatePanel 内部有一个 Repeater(其 id 显示在 ModalPopupExtender 内部)。Repeater 使用 MyDTO 对象的数组列表进行数据绑定。列表中的每个项目都有两个按钮。绑定后ImageURL 和 CommandArgument 已设置。
此代码第一次工作正常,但 CommandArgument 似乎已正确更新,但 DTO 未正确发送,并且发送的 CommandArgument 是刚刚被删除的
。发现代码有任何问题吗?
编辑:我刚刚在代码中添加了一个 CollapsiblePanelExtender,当我现在删除一个项目并展开面板时,之前删除的项目(并从显示中消失)又回来了。看来中继器尚未在引擎盖下正确重建。
ASCX
<asp:UpdatePanel ID="ViewDataDetail" runat="server" ChildrenAsTriggers="true">
<Triggers>
<asp:PostBackTrigger ControlID="ViewDataCloseButton" />
<asp:AsyncPostBackTrigger ControlID="DataRepeater" />
</Triggers>
<ContentTemplate>
<table width="100%" id="DataResults">
<asp:Repeater ID="DataRepeater" runat="server" OnItemCommand="DataRepeater_ItemCommand" OnItemDataBound="DataRepeater_ItemDataBound">
<HeaderTemplate>
<tr>
<th><b>Name</b></th>
<th><b> </b></th>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td>
<b><%#((MyDTO)Container.DataItem).Name%></b>
</td>
<td>
<asp:ImageButton CausesValidation="false" ID="DeleteData" CommandName="Delete" runat="server" />
<asp:ImageButton CausesValidation="false" ID="RunData" CommandName="Run" runat="server" />
</td>
</tr>
<tr>
<td colspan="2">
<table>
<tr>
<td>Description : </td>
<td><%#((MyDTO)Container.DataItem).Description%></td>
</tr>
<tr>
<td>Search Text : </td>
<td><%#((MyDTO)Container.DataItem).Text%></td>
</tr>
</table>
</td>
</tr>
</ItemTemplate>
</asp:Repeater>
</table>
</ContentTemplate>
</asp:UpdatePanel>
代码隐藏
public DeleteData DeleteDataDelegate;
public RetrieveData PopulateDataDelegate;
public delegate ArrayList RetrieveData();
public delegate void DeleteData(String sData);
protected void Page_Load(object sender, EventArgs e)
{
//load the initial data..
if (!Page.IsPostBack)
{
if (PopulateDataDelegate != null)
{
this.DataRepeater.DataSource = this.PopulateDataDelegate();
this.DataRepeater.DataBind();
}
}
}
protected void DataRepeater_ItemCommand(object source, RepeaterCommandEventArgs e)
{
if (e.CommandName == "Delete")
{
if (DeleteDataDelegate != null)
{
DeleteDataDelegate((String)e.CommandArgument);
BindDataToRepeater();
}
}
else if (e.CommandName == "Run")
{
String sRunning = (String)e.CommandArgument;
this.ViewDataModalPopupExtender.Hide();
}
}
protected void DataRepeater_ItemDataBound(object source, RepeaterItemEventArgs e)
{
RepeaterItem item = e.Item;
if (item != null && item.DataItem != null)
{
MyDTO oQuery = (MyDTO)item.DataItem;
ImageButton oDeleteControl = (ImageButton) item.FindControl("DeleteData");
ImageButton oRunControl = (ImageButton)item.FindControl("RunData");
if (oDeleteControl != null && oRunControl !=null)
{
oRunControl.ImageUrl = "button_expand.gif";
oRunControl.CommandArgument = "MyID";
if (oQuery !=null)
{
//do something
}
oDeleteControl.ImageUrl = "btn_remove.gif";
oDeleteControl.CommandArgument = "MyID";
}
}
}
public void BindDataToRepeater()
{
this.DataRepeater.DataSource = this.PopulateDataDelegate();
this.DataRepeater.DataBind();
}
public void ShowModal(object sender, EventArgs e)
{
BindDataToRepeater();
this.ViewDataModalPopupExtender.Show();
}
In a user control, I've got a Repeater inside of an UpdatePanel (which id displayed inside of a ModalPopupExtender. The Repeater is databound using an array list of MyDTO objects. There are two buttons for each Item in the list. Upon binding the ImageURL and CommandArgument are set.
This code works fine the first time around but the CommandArgument is wrong thereafter. It seems like the display is updated correctly but the DTO isn't and the CommandArgument sent is the one that has just been removed.
Can anybody spot any problems with the code?
Edit : I've just added a CollapsiblePanelExtender to the code. When I now delete an item and expand the panel, the item that was previously deleted (and gone from the display) has come back. It seems that the Repeater hasn't been rebuilt correctly under the bonnet.
ASCX
<asp:UpdatePanel ID="ViewDataDetail" runat="server" ChildrenAsTriggers="true">
<Triggers>
<asp:PostBackTrigger ControlID="ViewDataCloseButton" />
<asp:AsyncPostBackTrigger ControlID="DataRepeater" />
</Triggers>
<ContentTemplate>
<table width="100%" id="DataResults">
<asp:Repeater ID="DataRepeater" runat="server" OnItemCommand="DataRepeater_ItemCommand" OnItemDataBound="DataRepeater_ItemDataBound">
<HeaderTemplate>
<tr>
<th><b>Name</b></th>
<th><b> </b></th>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td>
<b><%#((MyDTO)Container.DataItem).Name%></b>
</td>
<td>
<asp:ImageButton CausesValidation="false" ID="DeleteData" CommandName="Delete" runat="server" />
<asp:ImageButton CausesValidation="false" ID="RunData" CommandName="Run" runat="server" />
</td>
</tr>
<tr>
<td colspan="2">
<table>
<tr>
<td>Description : </td>
<td><%#((MyDTO)Container.DataItem).Description%></td>
</tr>
<tr>
<td>Search Text : </td>
<td><%#((MyDTO)Container.DataItem).Text%></td>
</tr>
</table>
</td>
</tr>
</ItemTemplate>
</asp:Repeater>
</table>
</ContentTemplate>
</asp:UpdatePanel>
Code-Behind
public DeleteData DeleteDataDelegate;
public RetrieveData PopulateDataDelegate;
public delegate ArrayList RetrieveData();
public delegate void DeleteData(String sData);
protected void Page_Load(object sender, EventArgs e)
{
//load the initial data..
if (!Page.IsPostBack)
{
if (PopulateDataDelegate != null)
{
this.DataRepeater.DataSource = this.PopulateDataDelegate();
this.DataRepeater.DataBind();
}
}
}
protected void DataRepeater_ItemCommand(object source, RepeaterCommandEventArgs e)
{
if (e.CommandName == "Delete")
{
if (DeleteDataDelegate != null)
{
DeleteDataDelegate((String)e.CommandArgument);
BindDataToRepeater();
}
}
else if (e.CommandName == "Run")
{
String sRunning = (String)e.CommandArgument;
this.ViewDataModalPopupExtender.Hide();
}
}
protected void DataRepeater_ItemDataBound(object source, RepeaterItemEventArgs e)
{
RepeaterItem item = e.Item;
if (item != null && item.DataItem != null)
{
MyDTO oQuery = (MyDTO)item.DataItem;
ImageButton oDeleteControl = (ImageButton) item.FindControl("DeleteData");
ImageButton oRunControl = (ImageButton)item.FindControl("RunData");
if (oDeleteControl != null && oRunControl !=null)
{
oRunControl.ImageUrl = "button_expand.gif";
oRunControl.CommandArgument = "MyID";
if (oQuery !=null)
{
//do something
}
oDeleteControl.ImageUrl = "btn_remove.gif";
oDeleteControl.CommandArgument = "MyID";
}
}
}
public void BindDataToRepeater()
{
this.DataRepeater.DataSource = this.PopulateDataDelegate();
this.DataRepeater.DataBind();
}
public void ShowModal(object sender, EventArgs e)
{
BindDataToRepeater();
this.ViewDataModalPopupExtender.Show();
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
感谢您提醒我为什么停止使用 ASP.NET 控件。这正是导致太多项目超出预算和进度的噩梦。
我给你的建议是想出最简单的方法来实现这一点。您可以尝试竭尽全力使其以 ASP.NET 方式工作或采取最短路线。
您所做的只是生成 HTML,它应该不会那么困难。
问题最可能的原因是 ViewState 存储在页面中,该页面在部分回发时不会更新。因此,随着更新面板中的每次更改,您都将回发页面的初始视图状态。
尝试用简单的 for 循环替换转发器(并忽略那些开始抱怨你不应该混合标记和代码的人)。将数据绑定语句替换为
<%= %>
。这会完全消除视图状态,并且应该删除所有已删除的行,使其不再重新出现。
Thanks for reminding me why I stopped using ASP.NET controls. This is the exact type of nightmare that has made too many projects go way over budget and schedule.
My advise to you is to think of the simplest way to implement this. You can try to bend over backwards in order to get this to work the ASP.NET way or take the shortest route.
All you're doing is generating HTML, it should never be that difficult.
The most likely cause of your problem is that the ViewState is stored in the page which doesn't get updated on a partial postback. So with every change in the update panel you'll postback the initial viewstate of the page.
Try replacing the repeater with a simple for-loop (and ignore the people who start complaining you shouldn't mix markup and code). Replace your databinding statements with
<%= %>
.That eliminates the view state all together and should remove any removed row from re-appearing.
经过很多天的折腾,我还没有找到解决该问题的正确方法,但确实有一个可行的解决方法。
CollapsiblePanelExtender 设置为“不自动回发”,这解决了打开扩展器时已删除的数据重新出现的问题。我认为另一个问题是相关的。
中继器的 ViewState 似乎与数据不同步。 e.CommandArgument 并不总是正确的,并且似乎引用了以前的数据。我尝试通过在打开模态对话框时将 MyDTO 对象的 ArrayList 存储在 ViewState 中并使用从 e.Item.ItemIndex 检索到的 ID 来查找要删除的正确元素来修复此问题。这无法正常工作,从 ViewState 中拉出的 ArrayList 不同步。
将 ArrayList 存储在会话中使得一切正常工作,这让我相信我正在做一些根本错误的事情,或者我正在使用的工具包版本中存在一个微妙的错误(我们仍在 VS2005 上,所以被卡住了)使用旧版本的工具包)
如果这没有意义,请与我联系,如果您想澄清任何事情。
After many days of messing around with this I've not found a proper fix for the problem but do have a workable work-around.
The CollapsiblePanelExtender is set to NOT postback automatically which fixes the issue of the deleted data re-appearing when the extender is opened. The other issue, I believe, is related.
It seems that the ViewState for the Repeater is out of sync with the data. e.CommandArgument is not always correct and seems to reference the previous data. I made an attempt to fix it by storing the ArrayList of MyDTO objects in the ViewState when opening the Modal dialog and using the ID retrieved from e.Item.ItemIndex to find the correct element to delete. This didn't work correctly, the ArrayList pulled out of the ViewState was out of sync.
Storing the ArrayList in the session makes it all work which leads me to believe that I'm doing something fundamentally wrong or there is a subtle bug in the version of the toolkit that i'm using (we're still on VS2005 so are stuck with an older version of the toolkit)
Apologies if this makes no sense, contact me if you want clarification on anything.
尝试使用
而不是“
Container.DataItem
”它对我有用。
try using
instead of "
Container.DataItem
"It worked for me.