如何在不使用数据库的情况下重新实例化动态 ASP.NET 用户控件? [英] How can I re-instantiate dynamic ASP.NET user controls without using a database?

查看:23
本文介绍了如何在不使用数据库的情况下重新实例化动态 ASP.NET 用户控件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在使用我的应用程序的一部分,它使用动态 Web 用户控件,我在找出使用 ViewState 或其他一些方法来重新实例化回发控件的最佳方法时遇到了一些麻烦不需要我在每次回发时查询数据库.

我的页面上基本上是一个用户控件,它包含一个用于容纳可变数量的子用户控件的面板和一个显示添加控件"的按钮,其功能非常不言自明.

子用户控件非常简单;它只是一个删除按钮、一个下拉菜单和一个排成一行的时间选择器控件.每当用户单击父控件上的添加控件"按钮时,都会在包含子控件的面板中添加一个新的行".

我想做的是能够向这个集合添加和删除控件、修改值以及执行我需要在内存中"执行的任何操作,而无需对数据库进行任何调用.当我完成添加控件并填充它们的值时,我想单击保存"以一次将所有数据从控件保存/更新到数据库.目前我发现的唯一解决方案是在每次回发时简单地将数据保存在数据库中,然后使用存储在数据库中的行来重新实例化回发时的控件.显然,这迫使用户违背自己的意愿将更改保存到数据库,如果他们想取消使用控件而不保存数据,则必须进行额外的工作以确保删除先前提交的行.

根据我对使用动态控件的了解,我知道最好在生命周期的 Init 阶段将控件添加到页面,然后在加载阶段填充它们的值.我还了解到,确保您可以保持控件的视图状态的唯一方法是确保为每个动态控件提供唯一的 ID,并确保在重新实例化控件时为其分配完全相同的 ID.我还了解到 ViewState 直到生命周期的 Init 阶段之后才真正被加载.这就是我的问题所在.如果我无法使用视图状态并且不想对数据库执行任何调用,如何存储和检索这些控件的名称?使用 ASP.net 甚至可以进行这种内存操作/批量保存值吗?

非常感谢任何帮助,

迈克

解决方案

您可以存储在会话中保存的集合中重新创建控件所需的最少知识.会话在页面的初始化阶段可用.

这是给你的一个例子.它包括:

默认.aspx, cs
- 用于存储用户控件的面板
- 添加控件按钮",每次点击都会添加一个用户控件

TimeTeller.ascx, cs
- 有一个名为 SetTime 的方法,它将控件上的标签设置为指定时间.

默认.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="DynamicControlTest._Default" %><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 过渡//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" ><head runat="服务器"><标题></标题></头><身体><form id="form1" runat="server">

<asp:Panel ID="pnlDynamicControls" runat="server"></asp:面板><br/><asp:Button ID="btnAddControl" runat="server" Text="添加用户控件"onclick="btnAddControl_Click"/></div></表格></身体></html>

默认.aspx.cs:

使用系统;使用 System.Collections.Generic;使用 System.Linq;使用 System.Web;使用 System.Web.UI;使用 System.Web.UI.WebControls;命名空间 DynamicControlTest{公共部分类_默认:System.Web.UI.Page{字典<字符串,字符串>我的控制列表;//ID,控制 ascx 路径protected void Page_Load(object sender, EventArgs e){}受保护的覆盖无效 OnInit(EventArgs e){base.OnInit(e);如果(!IsPostBack){myControlList = new Dictionary<string, string>();会话["myControlList"] = myControlList;}别的{myControlList =(字典<字符串,字符串>)会话[myControlList"];foreach(myControlList.Keys 中的 var 注册控制 ID){UserControl controlToAdd = new UserControl();controlToAdd = (UserControl)controlToAdd.LoadControl(myControlList[registeredControlID]);controlToAdd.ID = 注册控制ID;pnlDynamicControls.Controls.Add(controlToAdd);}}}protected void btnAddControl_Click(对象发送者,EventArgs e){UserControl controlToAdd = new UserControl();controlToAdd = (UserControl)controlToAdd.LoadControl("TimeTeller.ascx");//设置一个值来证明 viewstate 是有效的((TimeTeller)controlToAdd).SetTime(DateTime.Now);controlToAdd.ID = Guid.NewGuid().ToString();//不必是一个 guid,只是一些独特的东西以避免名称冲突.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:标签 ID="lblTime" runat="server"/>

TimeTeller.ascx.cs

使用系统;使用 System.Collections.Generic;使用 System.Linq;使用 System.Web;使用 System.Web.UI;使用 System.Web.UI.WebControls;命名空间 DynamicControlTest{公共部分类 TimeTeller:System.Web.UI.UserControl{protected void Page_Load(object sender, EventArgs e){}public void SetTime(DateTime 时间){lblTime.Text = time.ToString();}受保护的覆盖无效LoadViewState(对象已保存状态){base.LoadViewState(savedState);lblTime.Text = (string)ViewState["lblTime"];}受保护的覆盖对象 SaveViewState(){ViewState["lblTime"] = lblTime.Text;返回 base.SaveViewState();}}}

如您所见,我仍然需要管理用户控件的内部视图状态,但视图状态包正在保存到页面并在回发时交回给控件.我认为重要的是要注意我的解决方案非常接近大卫的解决方案.我的示例中唯一的主要区别是它使用会话而不是视图状态来存储控制信息.这允许在初始化阶段发生一些事情.请务必注意,此解决方案会占用更多服务器资源,因此在某些情况下可能不合适,具体取决于您的扩展策略.

I'm currently working with a part of my application that uses Dynamic Web User Controls and I'm having a bit of trouble figuring out the best way to re-instantiate the controls on postback by using ViewState or some other method that doesn't require me to query a database on each postback.

Basically what I have on my page is a user control that contains a panel for holding a variable amount of child user controls and a button that says "Add Control" whose function is pretty self explanatory.

The child user control is pretty simple; it's just a delete button, a drop down, and a time picker control arranged in a row. Whenever the user clicks the Add Control button on the parent control, a new 'row' is added to the panel containing the child controls.

What I would like to do is to be able to add and remove controls to this collection, modify values, and perform whatever operations I need to do 'in-memory' without having to do any calls to a database. When I am done adding controls and populating their values, I'd like to click "save" to save/update all the data from the controls to a database at once. Currently the only solution I have found is to simply save the data in the database each post back and then use the rows stored in the db to re-instantiate the controls on postback. Obviously, this forces the user to save changes to the DB against their will and in the event that they want to cancel working with the controls without saving their data, extra work must be done to ensure that the rows previously committed are deleted.

From what I've learned about using dynamic controls, I know it's best to add the controls to the page during the Init stage of the lifecycle and then populate their values in the load stage. I've also learned that the only way to make sure you can persist the control's viewstate is to make sure you give each dynamic control a unique ID and be sure to assign it the exact same ID when re instantiating the control. I've also learned that the ViewState doesn't actually get loaded until after the Init stage in the life cycle. This is where my problem lies. How do I store and retrieve the names of these controls if I am unable to use the viewstate and I do not want to perform any calls to a database? Is this sort of in-memory manipulation / batch saving of values even possible using ASP.net?

Any help is greatly appreciated,

Mike

解决方案

You could store the bare minimum of what you need to know to recreate the controls in a collection held in session. Session is available during the init phases of the page.

Here is an example for you. It consists of:

Default.aspx, cs
- panel to store user controls
- "Add Control Button" which will add a user control each time it is clicked

TimeTeller.ascx, cs
- has a method called SetTime which sets a label on the control to a specified time.

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();
      }
   }
}  

As you can see, I still have to manage the internal viewstate of my user control, but the viewstate bag is being saved to the page and handed back to the control on postback. I think it is important to note that my solution is very close to David's. The only major difference in my example is that it's using session instead of viewstate to store the control info. This allows things to happen during the initialization phase. It is important to note that this solution takes up more server resources, therefore it may not be appropriate in some situations depending on your scaling strategy.

这篇关于如何在不使用数据库的情况下重新实例化动态 ASP.NET 用户控件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆