c#.net使用向导控件从动态框保持控制状态

时间:2012-01-11 11:14:12

标签: c# asp.net user-controls viewstate wizard

我遇到了一些问题,试图在作为用户控件(.ascx)文件一部分的向导中的回发之间保持文本框控件中的值状态。

一些背景

这是一个产品的订单,可以有不同的选项(1个产品可以有很多选项),因此选项不是通用的。 使用语法“OptionBox-4”(最后的数字为ID),向导的“开始”阶段向用户显示选项列表(使用SubSonic 2从数据库中提取)数据库中的选项,以便我可以稍后返回并获取说明。

然后,用户可以在每个选项中输入不同的数量。

问题

一旦用户在框中输入了数量,然后点击“下一步”,则不会在回发之间或控件的ID之间存储值。

代码

<asp:Wizard ID="Wizard1" runat="server" ActiveStepIndex="0"
    DisplaySideBar="False" onnextbuttonclick="Wizard1_NextButtonClick" 
    onpreviousbuttonclick="Wizard1_PreviousButtonClick" 
    FinishCompleteButtonText="Submit request"  
    onfinishbuttonclick="Wizard1_FinishButtonClick" 
    onactivestepchanged="Wizard1_ActiveStepChanged" 
    onprerender="Wizard1_PreRender" >
    <FinishPreviousButtonStyle CssClass="subbutton" />
    <FinishCompleteButtonStyle CssClass="subbutton" />
    <StartNextButtonStyle CssClass="subbutton" />
    <StepNextButtonStyle CssClass="subbutton" />
    <StepPreviousButtonStyle CssClass="subbutton" />
    <WizardSteps>
        <asp:WizardStep runat="server" StepType="Start" title="Description" ID="vgStep1">
            <fieldset class="emailform">
            <ul runat="server" id="optionList">
                <asp:PlaceHolder id="DynamicBoxes" runat="server" />
            </ul>
            </fieldset>
        </asp:WizardStep>
        <asp:WizardStep ID="WizardStep1" runat="server" Title="Your details" StepType="Finish">
            <h3>Order summary</h3>
            <asp:Literal ID="ltlSummary" runat="server"></asp:Literal>
        </asp:WizardStep>
        <asp:WizardStep ID="WizardStep2" runat="server" StepType="Complete" Title="Thank you">

        </asp:WizardStep>
    </WizardSteps>
</asp:Wizard>

相关代码隐藏

    class ResponseCollection : List<string> { }
private int? NrOfOptions
{
    get { return (int?)ViewState["NrOfOptions"]; }
    set { ViewState["NrOfOptions"] = value; }
}
public PartnerProductOrderableOptionCollection colOptions;
public PartnerProductOrderable prodOrderable;

protected void Page_Load(object sender, EventArgs e)
{
    LoadOrderWizard(Utility.GetPartnerProductId(Request.QueryString["ppid"]));
    CreateDynamicBoxes();
}

#region Ordering wizard
private void LoadOrderWizard(int p)
{

    partnerProduct = new PartnerProduct(p);

    prodOrderable = new PartnerProductOrderable("PartnerProductId", p);

    colOptions = new PartnerProductOrderableOptionCollection();
    colOptions.LoadAndCloseReader(PartnerProductOrderableOption.FetchByParameter("OrderableId", prodOrderable.OrderableId, OrderBy.Asc("ListOrder")));
    if (!IsPostBack)
    {
        this.NrOfOptions = colOptions.Count;
    }
}

protected void Wizard1_ActiveStepChanged(object sender, EventArgs e)
{
    if (Wizard1.ActiveStepIndex == 1)
    {
        ResponseCollection responses = CollectValuesFromDynamicBoxes();
        ltlSummary.Text += "Controls:";
        foreach (Control c in DynamicBoxes.Controls)
        {
            ltlSummary.Text += c.ID + ",";
            if (c is TextBox)
            {
                ltlSummary.Text += ((TextBox)c).ID + ",";
                if (!String.IsNullOrEmpty(((TextBox)c).Text))
                {
                    int optionid = int.Parse(c.ID.Split('-')[1]);
                    PartnerProductOrderableOption o = new PartnerProductOrderableOption(optionid);
                    ltlSummary.Text += "<strong>Quantity: </strong>" + ((TextBox)c).Text + "<br />";
                    ltlSummary.Text += "<strong>Description: </strong>" + o.Description + " - " + o.Price + "<hr />";

                }
            }
        }
    }
}

protected void Wizard1_PreviousButtonClick(object sender, WizardNavigationEventArgs e)
{
}

protected void Wizard1_FinishButtonClick(object sender, WizardNavigationEventArgs e)
{
    ResponseCollection responses = CollectValuesFromDynamicBoxes();
}
protected void Wizard1_NextButtonClick(object sender, WizardNavigationEventArgs e)
{
    if (e.CurrentStepIndex == 0)
    {
        int newNumberOfOptions = colOptions.Count;
        int? oldNumberOfOptions = this.NrOfOptions;


        if (!oldNumberOfOptions.HasValue || newNumberOfOptions != oldNumberOfOptions.Value)
        {
            this.NrOfOptions = newNumberOfOptions;

            CreateDynamicBoxes();
        }
    }
}
private void CreateDynamicBoxes()
{
    if (!this.NrOfOptions.HasValue)
        return;

    DynamicBoxes.Controls.Clear();

    foreach (PartnerProductOrderableOption opt in colOptions)
    {
        HtmlGenericControl li = new HtmlGenericControl("li");
        DynamicBoxes.Controls.Add(li);

        TextBox box = new TextBox();
        box.ID = "OptionBox-" + opt.OptionId;
        box.Width = 40;
        box.MaxLength = 6;

        li.Controls.Add(box);

        Label lblOpt = new Label();
        lblOpt.ID = "lblOption-" + opt.OptionId;
        lblOpt.Text = opt.Description + " - " + opt.Price;
        li.Controls.Add(lblOpt);
    }
    this.NrOfOptions= colOptions.Count;
}

private ResponseCollection CollectValuesFromDynamicBoxes()
{
    ResponseCollection responses = new ResponseCollection();
    for (int i = 0; i < this.NrOfOptions.Value; i++)
    {
        TextBox box = (TextBox)DynamicBoxes.FindControl("OptionBox-" + i);
        string response = box.Text.Trim();

        if (response.Length > 0)
            responses.Add(response);
    }
    return responses;
}


protected void Wizard1_PreRender(object sender, EventArgs e)
{

}

protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);

}

#endregion

代码基于http://aspnetresources.com/blog/dynamic_text_bBoxes_in_wizard_control,它似乎与我需要的东西非常相似。

另一个注释

必须在Page_Load事件中调用LoadOrderWizard方法。这是一个精简代码,只显示与我的问题相关的代码。控件实际上由几个不同的面板组成,这些面板根据传递给控件的数据显示不同的信息。因此,Page_Init事件中的初始化代码将不必要地触发。

2 个答案:

答案 0 :(得分:0)

尝试将CreateDynamicBoxes()移动到Page_Init

protected void Page_Init(object sender, EventArgs e)
{
    CreateDynamicBoxes();
}

答案 1 :(得分:0)

最后,因为我找不到一个可行的解决方案,我最终使用会话变量来存储动态框的id和包含的值。然后我在其他页面上检查文本框ID是否包含在会话中,并将其值恢复到框中。

由于只有数字放在此框中,此解决方案对我来说是一种解决方法。但是,知道是否有另一种解决方案仍然很好。