我正在开发一个ASP.NET VB.NET Web表单 - 一个预订Web应用程序,其中只有一个aspx页面和其余部分是用户控制页面。
在aspx页面的运行时,用户控制按照步骤加载,名称在db中定义,如下面的链接。
ASP.NET Custom user control to add dynamically
在第一步中,第一个用户控件是在page-init中绑定,用于显示.NET datalist控件中的预留可用性详细信息,如(参见图像)。
绑定所有细节以通过data-list的item_databound事件生成运行时控件。
现在问题是每当任何datalist事件(点击romm-image或下拉选择索引改变)被触发时,动态控件就像ammenities,其他行的动态下拉等删除。
我尝试过: - ispostback,页面生命周期的相关事件,ajax-jquery,viewstate。
我也查了一下,但没有运气。 : Dynamically added controls in Asp.Net
我分析一下,用户控件总是反弹,然后事件被触发,但没有数据列表重新绑定,因此没有 - 数据绑定事件触发,最后动态控制被删除。如果您愿意,我也会分享代码(但代码很大)。
所以问题是如何在下拉选择索引更改或在usercontrol中的datalist中触发图像点击事件时保留动态控件及其值?
我没有使用更新面板,这有用吗?如果是,那么请提供样本数据。
很好地回答样本数据。即使请通过网格视图等任何其他控件建议,如果可能的话,我准备改变它。
更新 这是我的代码
加载用户控制代码 在aspx页面中,usercontrol定义根据当前步骤加载另一个用户控件。 aspx页面中的“uc”用户控件标记。
<div id="divPlaceholder" runat="server">
<uc:DynamicControlHost ID="ucDynamicControlHost" runat="server" />
</div>
在page_load和page_prerender(ispostback)中,下面的代码执行以加载运行时用户控件。
public Control SetUserControlPath(string path)
{
Control c = null;
if (this.dynamicAllContent.Controls.Count > 0)
{
//Check that the new control is not the same as the current control
if (!this.UserControlPath.Equals(path))
{
//Remove the old item because we can not simply replace them!
this.dynamicPHAllContent.Controls.Clear();
c = Page.LoadControl(path + ".ascx");
c.ID = path;
//Add New Item
this.dynamicAllContent.Controls.Add(c);
lock (_userControlLockObject)
{
//Store the new path
_strUserControl = path;
}
}
}
else
{
c = Page.LoadControl(path + ".ascx");
c.ID = path;
this.dynamicAllContent.Controls.Add(c);
_strUserControl = path;
}
return c;
}
usercontrol中的datalist结构
<asp:UpdatePanel ID="EmployeesUpdatePanel" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:DataList ID="dlLodgingAvailableDetails" ShowHeader="true" OnSelectedIndexChanged="dlLodgingAvailableDetails_SelectedIndexChanged" runat="server" CellPadding="2" CellSpacing="2" BorderWidth="1px" BorderColor="Black"
OnItemDataBound="dlLodgingAvailableDetails_ItemDataBound" BorderStyle="Solid" GridLines="Horizontal" HorizontalAlign="Justify">
<HeaderStyle CssClass="submit_butt"></HeaderStyle>
<HeaderTemplate>
Lodging Item Type Details
<asp:Button ID="btnBookRoom" runat="server" Text="Book Rooms" CssClass="submit_butt" OnClick="btnBookRoom_Click" />
</HeaderTemplate>
<ItemTemplate>
<table cellpadding="2" cellspacing="0" border="1" style="width: 100%";>
<tr>
<td style="width:170px">
<asp:ImageButton ID="imgLodging" OnClick="imgLodging_Click" commandargument='<%# Eval("ItemTypeId") %>'
runat="server" ImageUrl='<%# Eval("Photo") %>' Width="150px" Height="120px" />
</td>
<td style="width:180px">
<b>Name</b><br />
<span><%# Eval("ItemTypeName") %></span><br />
<b>Occupancy</b> <span><%# Eval("Occupancy") %></span>
<br />
<asp:panel ID="placeholderAmmenities" runat="server" Visible="True" ></asp:panel>
</td>
<td style="width:100px">
<b>Room</b><br />
<asp:hiddenfield runat="server" ID="hdnItemTypeId" Value='<%# Eval("LodgingItemTypeId") %>' />
<asp:DropDownList ID="ddlAvailable" runat="server"
AppendDataBoundItems="True" SelectedValue='<%# Bind("LodgingReservationsAvailable") %>' >
<asp:ListItem Value="0" Text="0"/>
<asp:ListItem Value="1" Text="1"/>
<asp:ListItem Value="2" Text="2"/>
</asp:DropDownList>
</td>
<td>
</td>
<td style="width:100px">
<div id="dvadult" runat="server"></div>
<asp:placeholder runat="server" ID="PlaceHolderAdult" ViewStateMode="Enabled" EnableTheming="False" Visible="True" ></asp:placeholder>
</td>
<td style="width:50px">
<asp:Label runat="server" ID="lblnumbernight" ></asp:Label>
</td>
<td style="width:50px">
<asp:placeholder ID="placeholderPrice" runat="server" Visible="True"></asp:placeholder>
</td>
<td style="width:50px">
<b>Total</b><br />
<asp:Label runat="server" ID="lblTotalAmount" ></asp:Label>
</td>
<td style="width:100px">
<asp:Button ID="btnBookRoom" runat="server" Text="Book Rooms" CssClass="submit_butt" />
</td>
</tr>
</table>
</ItemTemplate>
<SeparatorStyle BackColor="Lime" Font-Bold="False" Font-Italic="False" Font-Overline="False" Font-Strikeout="False" Font-Underline="False" HorizontalAlign="Center" />
</asp:DataList>
</ContentTemplate>
</asp:UpdatePanel>
Datalist项目数据绑定事件代码(其内部图像绑定,价格相关字段添加并根据条件创建动态控件)
protected void dlLodgingAvailableDetails_ItemDataBound(object sender, DataListItemEventArgs e)
{
try
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
Image img = e.Item.FindControl("imgLodging") as Image;
if (img != null)
{
string bytesval = ((System.Data.DataRowView)(e.Item.DataItem)).Row.ItemArray[3].ToString();
if (string.IsNullOrWhiteSpace(bytesval)) return;
byte[] bytes = (byte[])((System.Data.DataRowView)(e.Item.DataItem)).Row.ItemArray[3];
string base64String = Convert.ToBase64String(bytes, 0, bytes.Length);
img.ImageUrl = "data:image/png;base64," + base64String;
}
DropDownList ddlList = e.Item.FindControl("ddlAvailable") as DropDownList;
Label lbldipositamount = e.Item.FindControl("lblTotalAmount") as Label;
Label lblnumbernight = e.Item.FindControl("lblnumbernight") as Label;
var PlaceHolderAmmenities = e.Item.FindControl("placeholderAmmenities") as Panel;
ddlList.Attributes.Add("onchange", " openLodgingNumber1(this,'" + ddlList.SelectedValue + "');");
int? LodgingItemTypeId = Convert.ToInt32(((System.Data.DataRowView)(e.Item.DataItem)).Row.ItemArray[1]);
DataSet ds = new DataSet();
ds = LodgingData.SelectLodgingItemTypeAmenityDateSet(LodgingItemTypeId);
DataTable dt = new DataTable();
if (ds != null)
{
dt = ds.Tables[0];
if (dt.Rows.Count > 0)
{
for (int j = 0; j < dt.Rows.Count; j++)
{
Image image = new Image();
image.ID = "imgAmmenities" + j + DateTime.Now.ToString();
string bytesval = dt.Rows[j]["AmenityIcon"].ToString(); //((System.Data.DataRowView)(e.Item.DataItem)).Row.ItemArray[4].ToStrin();
//if (string.IsNullOrWhiteSpace(bytesval)) return;
if (bytesval != string.Empty)
{
byte[] bytes = (byte[])dt.Rows[j]["AmenityIcon"];
string base64String = Convert.ToBase64String(bytes, 0, bytes.Length);
image.ImageUrl = "data:image/png;base64," + base64String;
image.Height = 20;
image.Width = 20;
image.EnableViewState = true;
PlaceHolderAmmenities.Controls.Add(image);
PlaceHolderAmmenities.Controls.Add(new LiteralControl(" "));
}
}
}
}
decimal PriceTotal = 0;
var PlaceHolderPrice = e.Item.FindControl("placeholderPrice") as PlaceHolder;
DataSet dsprice = new DataSet();
dsprice = LodgingData.SelectLodgingItemTypePrice(LodgingItemTypeId);
if (dsprice != null)
{
DataTable dtprice = new DataTable();
dtprice = dsprice.Tables[0];
if (dtprice.Rows.Count > 0)
{
DateTime fromdate = Convert.ToDateTime(txtFromDate.Text);
DateTime todate = Convert.ToDateTime(txtToDate.Text);
double daterange = ((todate - fromdate).TotalDays + 1);
lblnumbernight.Text = daterange.ToString();
//for (DateTime date = fromdate; date >= todate; date.AddDays(1))
for (int d = 0; d < Convert.ToInt32(daterange); d++ )
{
DateTime date = fromdate.AddDays(d);
//DataView dv = new DataView(dtprice);
DataTable dtprice1 = new DataTable();
DataRow[] rows = dtprice.Select("#" + date + "# >= PriceStartDate AND" + "#" + date + "# <= PriceEndDate");
if (rows.Length > 0)
{
dtprice1 = rows.CopyToDataTable();
}
if (dtprice1.Rows.Count > 0)
{
for (int j = 0; j < dtprice1.Rows.Count; j++)
{
Label lbl = new Label();
string dayofweek = dtprice1.Rows[j]["DayOfWeekId"].ToString();
if (dayofweek.Trim() == eDayOfWeek.All.ToString().Trim())
{
lbl.ID = "lbl" + j;
lbl.Text = dtprice1.Rows[j]["Price"].ToString();
PriceTotal += Convert.ToDecimal(dtprice1.Rows[j]["Price"]);
PlaceHolderPrice.Controls.Add(lbl);
PlaceHolderPrice.Controls.Add(new LiteralControl("<br />"));
}
else if (Convert.ToInt32(dayofweek) == Convert.ToInt32(date.DayOfWeek + 1))
{
lbl.ID = "lbl" + j;
lbl.Text = dtprice1.Rows[j]["Price"].ToString();
PriceTotal += Convert.ToDecimal(dtprice1.Rows[j]["Price"]);
PlaceHolderPrice.Controls.Add(lbl);
PlaceHolderPrice.Controls.Add(new LiteralControl("<br />"));
}
}
}
else
{
DataView dv1 = new DataView(dtprice);
dv1.RowFilter = "PriceStartDate IS NULL OR PriceEndDate IS NULL";
//dv1.RowFilter = "PriceStartDate == null and PriceEndDate == null";
DataTable dtprice2 = new DataTable();
dtprice2 = dv1.ToTable();
for (int j = 0; j < dtprice2.Rows.Count; j++)
{
Label lbl = new Label();
string dayofweek = dtprice2.Rows[j]["DayOfWeekId"].ToString();
if (dayofweek.Trim() == eDayOfWeek.All.ToString().Trim())
{
lbl.ID = "lbl" + j;
lbl.Text = dtprice2.Rows[j]["Price"].ToString();
PriceTotal += Convert.ToDecimal(dtprice2.Rows[j]["Price"]);
PlaceHolderPrice.Controls.Add(lbl);
PlaceHolderPrice.Controls.Add(new LiteralControl("<br />"));
}
else if (Convert.ToInt32(dayofweek) == Convert.ToInt32(date.DayOfWeek + 1))
{
lbl.ID = "lbl" + j;
lbl.Text = dtprice2.Rows[j]["Price"].ToString();
PriceTotal += Convert.ToDecimal(dtprice2.Rows[j]["Price"]);
PlaceHolderPrice.Controls.Add(lbl);
PlaceHolderPrice.Controls.Add(new LiteralControl("<br />"));
}
}
}
}
}
}
lbldipositamount.Text = PriceTotal.ToString();
// var amount = ((System.Data.DataRowView)(e.Item.DataItem)).Row.ItemArray[3];
int selectedvalue = Convert.ToInt32(ddlList.SelectedItem.Text);
if (selectedvalue != 0)
{
double totalamount = selectedvalue * Convert.ToDouble(PriceTotal);
lbldipositamount.Text = totalamount.ToString();
}
}
}
catch (Exception)
{
throw;
}
}
关于动态生成的下拉列表选择事件
在上面甚至动态地添加这个下拉列表,现在当调用此控件的事件时,进一步的动态控制正在根据条件添加。
问题是这个事件删除了动态的其他控件,即使前一个选择的其他行被隐藏或丢失,所以我们在任何帖子后退和事件触发时保留动态控件。
protected void ddlAvailable_SelectedIndexChanged(object sender, EventArgs e)
{
// if (UserControlTextBoxChanged != null) dlLodgingAvailableDetails_ItemDataBound(sender, e);
//dlLodgingAvailableDetails.ItemDataBound += new DataListItemEventHandler(dlLodgingAvailableDetails_ItemDataBound);
double amount = 0;
var ddlList = (DropDownList)sender;
var row = (DataListItem)ddlList.NamingContainer;
//get the Id of the row
DataSet ds = new DataSet();
int? Id = Convert.ToInt32(((HiddenField)row.FindControl("hdnItemTypeId")).Value);
double? tamount = Convert.ToDouble(((Label)row.FindControl("lblTotalAmount")).Text);
int? groupid = Convert.ToInt32(ddlLodgingGroup.SelectedValue);
int selectedvalue = Convert.ToInt32(ddlList.SelectedItem.Text);
DateTime? startdate = Convert.ToDateTime(txtFromDate.Text);
DateTime? enddate = Convert.ToDateTime(txtToDate.Text);
ds = LodgingData.SelectLodgingItemTypeDataSet(startdate, enddate, groupid);
DataTable dt = new DataTable();
DataView dv = new DataView();
if (ds != null)
{
dt = ds.Tables[0];
dv = dt.DefaultView;
dv.RowFilter = "LodgingItemTypeId=" + Id;
}
dt = dv.ToTable();
if (dt.Rows.Count > 0)
{
if (tamount != null)
{
amount = Convert.ToDouble(tamount);
}
}
//amount = Convert.ToDouble(((Label)row.FindControl("lblTotalAmount")).Text);
var PlaceHolder1 = ((PlaceHolder)row.FindControl("PlaceHolderAdult"));
double totalamount = 0;
if (selectedvalue != 0)
{
totalamount = selectedvalue * Convert.ToDouble(amount);
((Label)row.FindControl("lblTotalAmount")).Text = totalamount.ToString();
Label lblAdult = new Label();
lblAdult.ID = "lblAdult";
lblAdult.Text = "Adult";
lblAdult.Font.Bold = true;
PlaceHolder1.Controls.Add(lblAdult);
PlaceHolder1.Controls.Add(new LiteralControl("<br />"));
}
else
{
totalamount = amount;
}
for (int j = 0; j < selectedvalue; j++)
{
DropDownList ComboBox = new DropDownList();
ComboBox.ID = "ComboBox" + j;
ComboBox.AutoPostBack = false;
ComboBox.Attributes.Add("runat", "server");
ComboBox.Items.Add(new ListItem("0", "0"));
ComboBox.Items.Add(new ListItem("1", "1"));
ComboBox.Items.Add(new ListItem("2", "2"));
ComboBox.SelectedIndexChanged += new EventHandler(Dynamic_Method);
PlaceHolder1.Controls.Add(ComboBox);
PlaceHolder1.Controls.Add(new LiteralControl("<br />"));
}
}
答案 0 :(得分:3)
我不确定这会为您解决多少,但这里是一个使用包含动态生成的下拉列表的模板字段在gridview中保留一行数据的示例
我把这个过程分成两部分 1)将Gridview中当前的数据保存到会话变量中 2)重新创建,提供和绑定控件
这里保存gridview中的值。我使用我在这个网站上找到的递归查找控制公式(但不记得从哪里),因为我的控件生成并放在gridview行中而没有唯一的名称。对于前者第1行中存在的tbxA与第2行中的tbxA不同。这可能不适用于您 - 关键是找到要保存值的所有控件。
Private Sub SaveValues()
Dim savedTable As New DataTable
savedTable.Columns.Add(New DataColumn("A"))
For i = 0 To GridView1.Rows.Count - 1
Dim existing(0) As Object
existing(0) = TryCast(FindControlRecursive(GridView1.Rows(i), "ddlA"), DropDownList).SelectedValue
savedTable.Rows.Add(existing)
Next
Session("GhostTable") = savedTable
End Sub
然后在Page_Load下(当它是一个回发时)将gridview数据源设置为会话变量,并对其进行数据绑定。这将为每一行触发以下代码: 请记住,我还在页面加载时将下拉列表的数据源存储在会话变量中。这允许每次生成时都会为下拉列表发生数据源和数据绑定。
Protected Sub OnRowDataBound(sender As Object, e As GridViewRowEventArgs) Handles GridView1.RowDataBound
'Handles databinding of each gridview1 row ddl to gridview templatefield
If e.Row.RowType = DataControlRowType.DataRow Then
Dim ddlA As New DropDownList()
ddlA.DataSource = Session("lengthList")
ddlA.DataBind()
ddlA.ID = "ddlA"
ddlA.SelectedValue = TryCast(e.Row.DataItem, DataRowView).Row.Item("A").ToString()
e.Row.Cells(1).Controls.Add(ddlA)
End if
End Sub
ddlA.SelectedValue = TryCast(e.Row.DataItem, DataRowView).Row.Item("A").ToString()
是在任何回发后保留数据的内容。它确定绑定哪一行,然后用之前的任何内容重新填充控件。
希望这有帮助!
要确保每次都填充gridview,请在事件处理程序中调用SaveValues。
Protected Sub ddlEmpNumber_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ddlEmpNumber.SelectedIndexChanged
'Do whatever on selected index change, then the following:
Call SaveValues()
GridView1.DataSource = Session("GhostTable")
GridView1.DataBind()
End Sub
答案 1 :(得分:3)
您正在ASP部件中连接事件处理程序,如下所示:
<asp:DataList ID ... OnSelectedIndexChanged="dlLodgingAvailableDetails_SelectedIndexChanged" ...
然后在处理程序的代码中尝试重新连接其他代码:
ComboBox.SelectedIndexChanged += new EventHandler(Dynamic_Method);
每次在webforms页面上执行动态内容时,所有设置(包括事件处理程序wireup )必须位于page_init中。当事件发生时,重新布线不会起作用。对于你正在做的事情(asp:......并且在方法调用期间),它最终会出现在生命周期的错误部分,而正确的事情并不是要添加javascript调用doPostback,或者运行__eventargs等,还有尚未构建的控件的数据(事件回发在AFTER页面初始化时检查,因此你必须在检查之前创建控件)因此被忽略。
注意 - 可能你知道这一点,但是你必须给控件提供唯一的ID,如果你有一个数字主键,通常可以通过附加到数据行来完成。 (可能必须手动对用户控件中的子控件执行此操作,必须使用page_init中的usercontrols执行此操作,希望您赢了
我在一个大型应用程序上工作,该应用程序在page-init中动态构建webforms中的每个屏幕(来自UI生成器)。所有工作都是在活动中完成的,它们就像一个魅力! Page_load基本上是空的。了解asp页面生命周期 - 它是一个鼻屎但比在HotTowel中重写你的应用程序更容易(虽然想想下一个应用程序; - )
非常好的图表:http://blogs.msdn.com/b/aspnetue/archive/2010/01/14/asp-net-page-life-cycle-diagram.aspx
祝你好运!答案 2 :(得分:0)
我已经做了以上建议和其他谷歌搜索网站的所有事情。但它每次重新绑定网格中的所有动态对象时都会刷新数据。
最后我基于javascript和jquery做了所有事情,没有那个动态控件总是重新绑定我不想要的东西。因此,任何陷入这种情况的机构都会忘记使用动态控件和javascript / webmethod进行操作。
感谢所有给出答案的人