我试图让网页用户(ASP.NET WebForms)在WizardStep中添加动态的用户控件列表。我从没想过会有这么困难,但我不知道该如何做到这一点。我的最终目标是让用户在WizardStep中添加用户控件,并且如果用户转到不同的WizardStep(也就是向导进度),那么数据就会一直存在。我发现很难能够动态添加用户控件,而且如果用户离开此向导步骤,我也不知道如何保持用户控制。请帮忙!
答案 0 :(得分:2)
我没有动态创建UserControl,而是提出了一种涉及Repeater的方法。该方法还允许用户添加未知数量的项目,但避免了动态创建的控件的复杂性。为了实现真正动态的方法,您需要在每次回发的早期重新创建控件。如果不这样做,迟早会遇到麻烦,因为事件不会按预期触发,或者您无法检索用户已更改的数据。
因此,以下方法可避免动态创建控件,但使用Repeater显示UserControls。我选择了一个Repeater,以便在呈现的HTML方面保持灵活性。
根据您的评论,我创建了一个简单的 UserControl ,其中包含两个文本框:
<%@ Control Language="C#" AutoEventWireup="true"
CodeBehind="MyUserControl.ascx.cs"
Inherits="TestWizard.MyUserControl" %>
<table>
<tr>
<td>
<asp:TextBox ID="txt1" runat="server" />
</td>
<td>
<asp:TextBox ID="txt2" runat="server" />
</td>
</tr>
</table>
在UserControl的代码隐藏文件中,我定义了一个类,其中包含UserControl中使用的数据以及可用于获取和设置数据的属性:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace TestWizard
{
public class MyUserControlData
{
public string Text1 { get; set; }
public string Text2 { get; set; }
}
public partial class MyUserControl : System.Web.UI.UserControl
{
public MyUserControlData Data
{
get
{
return new MyUserControlData()
{ Text1 = txt1.Text, Text2 = txt2.Text };
}
set
{
txt1.Text = value.Text1;
txt2.Text = value.Text2;
}
}
}
}
我创建了一个页面,其中包含一个向导控件,包含3个步骤。第一个和最后一个是没用的,但第二步包含一个添加新项的按钮和一个在ItemTemplate中托管UserControl实例的Repeater。用于获取和设置数据的UserControl的属性绑定到RepeaterItem的DataItem。
<asp:Wizard ID="wiz" runat="server"
OnFinishButtonClick="wiz_FinishButtonClick">
<WizardSteps>
<asp:WizardStep runat="server">
<asp:Literal runat="server" Text="First Wizard Page" />
</asp:WizardStep>
<asp:WizardStep runat="server">
<asp:Button ID="btnAddNewEntry" runat="server"
Text="Add New Entry"
OnClick="btnAddNewEntry_Click" />
<asp:Repeater ID="rpt" runat="server">
<ItemTemplate>
<uc:MyUserCtrl ID="myUserCtrl" runat="server"
Data='<%# Container.DataItem %>' />
</ItemTemplate>
</asp:Repeater>
</asp:WizardStep>
<asp:WizardStep runat="server">
<asp:Literal runat="server" Text="Last Wizard Page" />
</asp:WizardStep>
</WizardSteps>
</asp:Wizard>
页面代码隐藏文件中一个非常重要的方法是从Repeater 检索数据的方法。它基本上迭代了Repeater的行,并在列表中收集Data属性。
private List<MyUserControlData> GetUserControlData()
{
var lst = new List<MyUserControlData>();
foreach(RepeaterItem item in rpt.Items)
{
var uc = item.FindControl("myUserCtrl") as MyUserControl;
if (uc != null)
lst.Add(uc.Data);
}
return lst;
}
此方法用于各种场合:首先,当向Repeater添加新项时,将检索现有内容并将新项添加到列表中:
protected void btnAddNewEntry_Click(object sender, EventArgs e)
{
var data = GetUserControlData();
var newData = new MyUserControlData()
{ Text1 = "New Item",
Text2 = "Created at " + DateTime.Now.ToString() };
data.Add(newData);
rpt.DataSource = data;
rpt.DataBind();
}
此外,当完成向导时,您可以通过以下方式检索数据:
protected void wiz_FinishButtonClick(object sender, WizardNavigationEventArgs e)
{
var data = GetUserControlData();
// Do something with the data
}
示例按预期工作,很容易检索用户输入文本框的数据。如果您有任何问题,请在评论中告诉我。
答案 1 :(得分:0)
这样做的方法是创建一个自定义类,如下所示:
public class WizardControl
{
public System.Web.UI.Control Control { get; set; }
public int WizardStep { get; set; }
}
然后在你的页面加载,创建(或加载)对象列表,如下所示:
if (_wizardControls==null)
{
if (ViewState["WizardControls"] == null)
_wizardControls = new List<WizardControl>();
else _wizardControls = (List<WizardControl>)ViewState["WizardControls"];
}
最后,在向导页面上,当用户选择控件时,请创建此类的实例:
var control = new WizardControl();
control.Control = _userSelectedControl; // Add whatever control the user selected
control.WizardStep = _wizardStep; // Set to whatever wizard page this control belongs to.
_wizardControls.Add(control); // Add it to our collection
ViewState["WizardControls"] = _wizardControls; // Save it into the ViewState