Как добавить элементы управления программно при нажатии кнопки?

У меня есть форма веб-сайта (С#), которая находится внутри элемента управления multiview. Управление мультипросмотром состоит из 4 шагов, поэтому первые 3 шага собирают информацию и, если они действительны, переходят к следующему представлению при нажатии кнопки.

Я хочу динамически построить форму на основе предыдущих ответов, но из того, что я прочитал до сих пор, я немного не уверен, как это сделать.

Например, на шаге 1 пользователь заполняет некоторые элементы управления текстовым полем и нажимает «Отправить».

На основе данных, представленных на панели 1, на следующей панели необходимо динамически создать ряд элементов управления — некоторые метки, некоторые текстовые поля.

Поскольку этот щелчок происходит после инициализации и загрузки страницы, я не уверен, как это будет работать.

Конечно, я мог бы создать все элементы управления метками/текстовыми полями заранее и отключить их по мере необходимости, но это, похоже, довольно плохое использование ресурсов.

Суть в том, что я неопытен в работе с динамическими элементами управления, поэтому любые советы будут оценены.


person dotnetnoob    schedule 16.11.2012    source источник
comment
Что вы делаете с данными со второй панели, есть ли кнопки, постбэки и т.д.? Если вы создаете элементы управления после OnInit, они все равно создаются, но данные обратной передачи не будут автоматически установлены. Поэтому, если вы вызываете обратные передачи на второй панели и вам нужны данные из этих динамических элементов управления, вам нужно получить эти данные в OnInit из Request.Forms[dynamicControlClientId] или, возможно, сохранить их в ViewState. Другая проблема заключается в том, нужно ли вам видеть динамические элементы управления после обратной передачи, поэтому вам нужно хранить информацию на второй панели, как создавать элементы управления для обратной передачи (условия из первой панели).   -  person pawciu    schedule 16.11.2012
comment
Да, будут дальнейшие постбеки. Всего в мультипросмотре 4 шага, поэтому первые 3 будут выполнять обратную передачу при переходе к следующему шагу.   -  person dotnetnoob    schedule 16.11.2012


Ответы (1)


Хорошо, ниже я вставил рабочий пример. Что нужно знать:

  • Чтобы избежать ошибки

Message=Failed to load viewstate. The control tree into which viewstate is being loaded must match the control tree that was used to save viewstate during the previous request. For example, when adding controls dynamically, the controls added during a post-back must match the type and position of the controls added during the initial request. Source=System.Web ErrorCode=-2147467259

установите это свойство в ваших динамических элементах управления

EnableViewState = false

Данные для этого примера выглядят так

Марка Двигатель Цвет Стоимость
VW, 1.2, Черный, 72 000
VW, 1.2, Белый, 70 000
VW, 1.6 TDI, Красный, 79 500
VW, 1.6 TDI, Белый, 78 800
Ford, 1.6, Черный, 57 600
Ford, 1.6, Зеленый, 57 100
Ford, 2.0 TDCi, Черный, 87 300
Ford, 2.0 TDCi, Белый, 86 600

В основном это работает так:

  • Выберите марку автомобиля и выберите кнопку (кнопка является нашим критерием для управления генерацией). Конечно, вы также можете использовать логику с раскрывающимися списками и т. Д.
  • На втором экране у вас есть один или два раскрывающихся списка в зависимости от вашего выбора.
  • Если у вас есть два раскрывающихся списка, второй зависит от выбора первого раскрывающегося списка, поэтому у вас есть пример зависимости и обратных передач.

Код страницы:

<form id="form1" runat="server">
<div>
<asp:MultiView ID="mvPanels" runat="server">
    <asp:View ID="vPanel1" runat="server">
        <table>
            <tbody>
                <tr>
                    <td>Pick car</td>
                    <td><asp:DropDownList ID="ddlBrand" runat="server" /></td>
                    <td><asp:Button ID="btnPanel1Next" Text="Next" runat="server" 
                            onclick="btnPanel1Next_Click" /></td>
                    <td><asp:Button ID="btnPanel1NextEngineOnly" Text="Next (pick engine only)" runat="server" 
                            onclick="btnPanel1NextEngineOnly_Click" /></td>
                </tr>
            </tbody>
        </table>
    </asp:View>
    <asp:View ID="vPanel2" runat="server">
        <%--<table>
            <tbody>
                <tr>
                    <td>Pick engine</td>
                    <td><asp:DropDownList ID="ddlEngine" AutoPostBack="true" runat="server" 
                            onselectedindexchanged="ddlEngine_SelectedIndexChanged" /></td>
                    <td><asp:DropDownList ID="ddlColor" AutoPostBack="true" runat="server" 
                            onselectedindexchanged="ddlColor_SelectedIndexChanged" /></td>
                    <td><asp:Button ID="btnPanel2Prev" Text="Prev" runat="server" 
                            onclick="btnPanel2Prev_Click" /><asp:Button ID="btnPanel2Next" Text="Next" 
                            runat="server" Enabled="False" onclick="btnPanel2Next_Click" /></td>
                </tr>
            </tbody>
        </table>--%>
    </asp:View>
    <asp:View ID="vPanel3" runat="server">
        <table>
            <tbody>
                <tr>
                    <td><asp:Label ID="lblResult" runat="server" /></td>
                    <td><asp:Button ID="btnPanel3Prev" Text="Prev" runat="server" 
                            onclick="btnPanel3Prev_Click" /><asp:Button ID="btnPanel3Finish" 
                            Text="Confirm" runat="server" onclick="btnPanel3Finish_Click" /></td>
                </tr>
            </tbody>
        </table>
    </asp:View>
</asp:MultiView>
</div>
</form>

Код позади:

public partial class Default : System.Web.UI.Page
{
    public class CarConfiguration
    {
        public string Brand { get; set; }
        public string Engine { get; set; }
        public PaintColor Paint { get; set; }
        public string Cost { get; set; }
    }

    [Serializable]
    public class CarConfigurationFilter
    {
        public string Brand { get; set; }
        public string Engine { get; set; }
        public PaintColor? Paint { get; set; }
        public bool EngineOnly { get; set; }
    }

    public enum PaintColor
    {
        Black,
        Red,
        White,
        Green,
    }

    public List<CarConfiguration> availableCars = new List<CarConfiguration>
    {
        new CarConfiguration{
            Brand = "VW",
            Engine = "1.2",
            Paint = PaintColor.Black,
            Cost = "72 000",
        },
        new CarConfiguration{
            Brand = "VW",
            Engine = "1.2",
            Paint = PaintColor.White,
            Cost = "70 000",
        },
        new CarConfiguration{
            Brand = "VW",
            Engine = "1.6 TDI",
            Paint = PaintColor.Red,
            Cost = "79 500"
        },
        new CarConfiguration{
            Brand = "VW",
            Engine = "1.6 TDI",
            Paint = PaintColor.White,
            Cost = "78 800",
        },
        new CarConfiguration{
            Brand = "Ford",
            Engine = "1.6",
            Paint = PaintColor.Black,
            Cost = "57 600"
        },
        new CarConfiguration{
            Brand = "Ford",
            Engine = "1.6",
            Paint = PaintColor.Green,
            Cost = "57 100"
        },
        new CarConfiguration{
            Brand = "Ford",
            Engine = "2.0 TDCi",
            Paint = PaintColor.Black,
            Cost = "87 300"
        },
        new CarConfiguration{
            Brand = "Ford",
            Engine = "2.0 TDCi",
            Paint = PaintColor.White,
            Cost = "86 600"
        },
    };

    CarConfigurationFilter filter
    {
        get { return (CarConfigurationFilter)ViewState["Filter"]; }
        set { ViewState["Filter"] = value; }
    }

    //If you have multiview in control you need to create this in event before event PageLoad like  LoadViewState, LoadControlState, LoadControlState
    protected override void OnPreLoad(EventArgs e)
    {
        if (IsPostBack && mvPanels.ActiveViewIndex == 1)
        {
            CreateControlsOnPanel2(true, !filter.EngineOnly);
        }
        base.OnPreLoad(e);
    }

    protected override void OnLoad(EventArgs e)
    {
        if (!IsPostBack)
        {
            ddlBrand.DataSource = availableCars.Select(x => x.Brand).Distinct();
            ddlBrand.DataBind();
            filter = new CarConfigurationFilter();
            mvPanels.ActiveViewIndex = 0;
        }
        base.OnLoad(e);
    }

    protected void btnPanel1Next_Click(object sender, EventArgs e)
    {
        filter.Brand = ddlBrand.SelectedValue;
        filter.EngineOnly = false;

        CreateControlsOnPanel2(true, true);

        mvPanels.ActiveViewIndex++; 
    }

    protected void btnPanel1NextEngineOnly_Click(object sender, EventArgs e)
    {
        filter.Brand = ddlBrand.SelectedValue;
        filter.EngineOnly = true;
        CreateControlsOnPanel2(true, false);

        mvPanels.ActiveViewIndex++; 
    }

    void CreateControlsOnPanel2(bool enginePickerEnabled, bool colorPickerEnabled)
    {
        var btnPanel2Prev = new Button();
        btnPanel2Prev.ID = "btnPanel1Prev";
        btnPanel2Prev.EnableViewState = false;    
        btnPanel2Prev.Text = "Prev";
        btnPanel2Prev.Click += btnPanel2Prev_Click;

        var btnPanel2Next = new Button();
        btnPanel2Next.ID="btnPanel2Next";
        btnPanel2Next.Text = "Next";
        btnPanel2Next.EnableViewState = false;
        btnPanel2Next.Enabled = false;
        btnPanel2Next.Click += btnPanel2Next_Click;


        if (enginePickerEnabled)
        {
            var ddlEngine = new DropDownList();
            ddlEngine.ID = "ddlEngine";
            ddlEngine.AutoPostBack = true;
            ddlEngine.EnableViewState = false;

            var engines = availableCars.Where(x => x.Brand == filter.Brand).Select(found => found.Engine).Distinct().ToList();
            engines.Insert(0, String.Empty);
            ddlEngine.DataSource = engines;
            ddlEngine.DataBind();
            if (!String.IsNullOrEmpty(filter.Engine))
            {
                ddlEngine.SelectedValue = filter.Engine;
                if (!colorPickerEnabled)
                    btnPanel2Next.Enabled = true;
            }
            else
                ddlEngine.SelectedIndex = 0;
            ddlEngine.SelectedIndexChanged += ddlEngine_SelectedIndexChanged;
            vPanel2.Controls.Add(ddlEngine);
        }
        //remember to add ID to all dynamic controls or there might be an error on postback
        if (colorPickerEnabled)
        {
            var ddlColor = new DropDownList();
            ddlColor.ID = "ddlColor";
            ddlColor.AutoPostBack = true;
            ddlColor.EnableViewState = false;
            ddlColor.SelectedIndexChanged += ddlColor_SelectedIndexChanged;
            vPanel2.Controls.Add(ddlColor);

            if (!String.IsNullOrEmpty(filter.Engine))
            {
                var colors = availableCars.Where(x => x.Brand == filter.Brand && x.Engine == filter.Engine).Select(found => found.Paint.ToString()).Distinct().ToList();
                colors.Insert(0, String.Empty);
                ddlColor.DataSource = colors;
                if (filter.Paint.HasValue)
                {
                    ddlColor.SelectedValue = filter.Paint.Value.ToString();
                    btnPanel2Next.Enabled = true;
                }

            }
            else
            {
                ddlColor.DataSource = null;
                ddlColor.SelectedIndex = 0;
            }
            ddlColor.DataBind();
        }

        vPanel2.Controls.Add(btnPanel2Prev);
        vPanel2.Controls.Add(btnPanel2Next);
    }

    protected void ddlEngine_SelectedIndexChanged(object sender, EventArgs e)
    {
        var ddlEngine = sender as DropDownList;
        var btnPanel2Next = (Button)vPanel2.FindControl("btnPanel2Next");

        if (!String.IsNullOrEmpty(ddlEngine.SelectedValue))
        {
            filter.Engine = ddlEngine.SelectedValue;
            var colors = availableCars.Where(x => x.Brand == filter.Brand && x.Engine == filter.Engine).Select(found => found.Paint.ToString()).Distinct().ToList();
            colors.Insert(0, String.Empty);
            filter.Paint = null;

            var ddlColor = (DropDownList)vPanel2.FindControl("ddlColor");
            if (ddlColor != null)
            {
                ddlColor.DataSource = colors;
                ddlColor.DataBind();
                ddlColor.SelectedIndex = 0;

                btnPanel2Next.Enabled = false;
            }
            else
                btnPanel2Next.Enabled = true;
        }
        else
        {
            var ddlColor = (DropDownList)vPanel2.FindControl("ddlColor");
            if (ddlColor != null)
            {
                ddlColor.Items.Clear();
                ddlColor.SelectedIndex = -1;
            }
            filter.Engine = null;
            btnPanel2Next.Enabled = false;
        }
    }

    protected void ddlColor_SelectedIndexChanged(object sender, EventArgs e)
    {
        var ddlColor = (DropDownList)vPanel2.FindControl("ddlColor");
        var btnPanel2Next = (Button)vPanel2.FindControl("btnPanel2Next");

        if (!String.IsNullOrEmpty(ddlColor.SelectedValue))
        {
            filter.Paint = (PaintColor)Enum.Parse(typeof(PaintColor), ddlColor.SelectedValue);
            btnPanel2Next.Enabled = true;
        }
        else
        {
            filter.Paint = null;
            btnPanel2Next.Enabled = false;
        }
    }

    protected void btnPanel2Prev_Click(object sender, EventArgs e)
    {
        filter.Engine = null;
        filter.Paint = null;
        mvPanels.ActiveViewIndex--;
    }

    protected void btnPanel2Next_Click(object sender, EventArgs e)
    {
        mvPanels.ActiveViewIndex++;

        var selectedConfiguration = availableCars.Where(x => x.Brand == filter.Brand && x.Engine == filter.Engine
        && (!filter.Paint.HasValue || x.Paint == filter.Paint)).Distinct().FirstOrDefault();
        if (selectedConfiguration != null)
            lblResult.Text = String.Format("You have selected {0} {1} {2} for {3} PLN", selectedConfiguration.Brand,
                selectedConfiguration.Engine, selectedConfiguration.Paint, selectedConfiguration.Cost);
    }

    protected void btnPanel3Prev_Click(object sender, EventArgs e)
    {
        mvPanels.ActiveViewIndex--;
        CreateControlsOnPanel2(true, !filter.EngineOnly);

    }

    protected void btnPanel3Finish_Click(object sender, EventArgs e)
    {
    }
}

Если есть дополнительные вопросы буду рад помочь

person pawciu    schedule 17.11.2012