基本上我在我的页面上有一个用户控件,它包含一个用于保存可变数量的子用户控件的面板和一个显示“Add Control”的按钮,其功能非常自我解释.
子用户控件非常简单;它只是一个删除按钮,一个下拉菜单和一个排成一排的时间选择器控件.每当用户单击父控件上的“添加控件”按钮时,都会向包含子控件的面板添加一个新的“行”.
我想要做的是能够添加和删除对该集合的控制,修改值,并执行我需要在内存中执行的任何操作,而无需对数据库进行任何调用.当我完成添加控件并填充其值时,我想单击“保存”以立即将控件中的所有数据保存/更新到数据库.目前我发现的唯一解决方案是简单地将每个帖子中的数据保存在数据库中,然后使用存储在数据库中的行来重新实例化回发上的控件.显然,这会强制用户根据自己的意愿保存对DB的更改,并且如果他们想要取消使用控件而不保存其数据,则必须进行额外的工作以确保删除先前提交的行.
根据我对使用动态控件的了解,我知道最好在生命周期的Init阶段将控件添加到页面,然后在加载阶段填充它们的值.我还了解到,确保您可以持久保存控件的视图状态的唯一方法是确保为每个动态控件提供唯一的ID,并确保在重新实例化控件时为其分配完全相同的ID.我还了解到ViewState实际上并没有在生命周期的Init阶段之后加载.这就是我的问题所在.如果我无法使用viewstate并且我不想对数据库执行任何调用,如何存储和检索这些控件的名称?是否可以使用ASP.net进行这种内存操作/批量保存值?
任何帮助是极大的赞赏,
麦克风
解决方法
这是一个例子给你.它包括:
Default.aspx,cs
– 用于存储用户控件的面板
– “添加控制按钮”,每次单击时都会添加用户控件
TimeTeller.ascx,cs
– 有一个名为SetTime的方法,它将控件上的标签设置为指定的时间.
Default.aspx的
- <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="DynamicControlTest._Default" %>
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
- <html xmlns="http://www.w3.org/1999/xhtml" >
- <head runat="server">
- <title></title>
- </head>
- <body>
- <form id="form1" runat="server">
- <div>
- <asp:Panel ID="pnlDynamicControls" runat="server">
- </asp:Panel>
- <br />
- <asp:Button ID="btnAddControl" runat="server" Text="Add User Control"
- onclick="btnAddControl_Click" />
- </div>
- </form>
- </body>
- </html>
Default.aspx.cs:
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
- using System.Web.UI;
- using System.Web.UI.WebControls;
- namespace DynamicControlTest
- {
- public partial class _Default : System.Web.UI.Page
- {
- Dictionary<string,string> myControlList; // ID,Control ascx path
- protected void Page_Load(object sender,EventArgs e)
- {
- }
- protected override void OnInit(EventArgs e)
- {
- base.OnInit(e);
- if (!IsPostBack)
- {
- myControlList = new Dictionary<string,string>();
- Session["myControlList"] = myControlList;
- }
- else
- {
- myControlList = (Dictionary<string,string>)Session["myControlList"];
- foreach (var registeredControlID in myControlList.Keys)
- {
- UserControl controlToAdd = new UserControl();
- controlToAdd = (UserControl)controlToAdd.LoadControl(myControlList[registeredControlID]);
- controlToAdd.ID = registeredControlID;
- pnlDynamicControls.Controls.Add(controlToAdd);
- }
- }
- }
- protected void btnAddControl_Click(object sender,EventArgs e)
- {
- UserControl controlToAdd = new UserControl();
- controlToAdd = (UserControl)controlToAdd.LoadControl("TimeTeller.ascx");
- // Set a value to prove viewstate is working
- ((TimeTeller)controlToAdd).SetTime(DateTime.Now);
- controlToAdd.ID = Guid.NewGuid().ToString(); // does not have to be a guid,just something unique to avoid name collision.
- pnlDynamicControls.Controls.Add(controlToAdd);
- myControlList.Add(controlToAdd.ID,controlToAdd.AppRelativeVirtualPath);
- }
- }
- }
TimeTeller.ascx
- <%@ Control Language="C#" AutoEventWireup="true" CodeBehind="TimeTeller.ascx.cs" Inherits="DynamicControlTest.TimeTeller" %>
- <asp:Label ID="lblTime" runat="server"/>
TimeTeller.ascx.cs
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
- using System.Web.UI;
- using System.Web.UI.WebControls;
- namespace DynamicControlTest
- {
- public partial class TimeTeller : System.Web.UI.UserControl
- {
- protected void Page_Load(object sender,EventArgs e)
- {
- }
- public void SetTime(DateTime time)
- {
- lblTime.Text = time.ToString();
- }
- protected override void LoadViewState(object savedState)
- {
- base.LoadViewState(savedState);
- lblTime.Text = (string)ViewState["lblTime"];
- }
- protected override object SaveViewState()
- {
- ViewState["lblTime"] = lblTime.Text;
- return base.SaveViewState();
- }
- }
- }
正如您所看到的,我仍然需要管理用户控件的内部视图状态,但viewstate包正在保存到页面并在回发时传回控件.我认为重要的是要注意我的解决方案与David的非常接近.我的例子中唯一的主要区别是它使用session而不是viewstate来存储控件信息.这允许在初始化阶段发生事情.请务必注意,此解决方案占用了更多服务器资源,因此在某些情况下可能不合适,具体取决于您的扩展策略.