views:

238

answers:

3

Hi,

I have a problem that has been bugging me all day.

In my code I have the following:

private int rowCount
    {
        get { return (int)ViewState["rowCount"]; }
        set { ViewState["rowCount"] = value; }
    }

and a button event

protected void addRow_Click(object sender, EventArgs e)
    {
        rowCount = rowCount + 1;
    }

Then on Page_Load I read that value and create controls accordingly.

I understand the button event fires AFTER the Page_Load fires so the value isn't updated until the next postback. Real nightmare.

Here's the entire code:

protected void Page_Load(object sender, EventArgs e)
    {
        string xmlValue = ""; //To read a value from a database
        if (xmlValue.Length > 0)
        {
            if (!Page.IsPostBack)
            {
                DataSet ds = XMLToDataSet(xmlValue);
                Table dimensionsTable = DataSetToTable(ds);
                tablePanel.Controls.Add(dimensionsTable);

                DataTable dt = ds.Tables["Dimensions"];
                rowCount = dt.Rows.Count;
                colCount = dt.Columns.Count;
            }
            else
            {
                tablePanel.Controls.Add(DataSetToTable(DefaultDataSet(rowCount, colCount)));
            }
        }
        else
        {
            if (!Page.IsPostBack)
            {
                rowCount = 2;
                colCount = 4;
            }
            tablePanel.Controls.Add(DataSetToTable(DefaultDataSet(rowCount, colCount)));
        }
    }

    protected void submit_Click(object sender, EventArgs e)
    {
        resultsLabel.Text = Server.HtmlEncode(DataSetToStringXML(TableToDataSet((Table)tablePanel.Controls[0])));
    }
    protected void addColumn_Click(object sender, EventArgs e)
    {
        colCount = colCount + 1;
    }

    protected void addRow_Click(object sender, EventArgs e)
    {
        rowCount = rowCount + 1;
    }

    public DataSet TableToDataSet(Table table)
    {
        DataSet ds = new DataSet();

        DataTable dt = new DataTable("Dimensions");
        ds.Tables.Add(dt);

        //Add headers
        for (int i = 0; i < table.Rows[0].Cells.Count; i++)
        {
            DataColumn col = new DataColumn();
            TextBox headerTxtBox = (TextBox)table.Rows[0].Cells[i].Controls[0];

            col.ColumnName = headerTxtBox.Text;
            col.Caption = headerTxtBox.Text;
            dt.Columns.Add(col);
        }


        for (int i = 0; i < table.Rows.Count; i++)
        {
            DataRow valueRow = dt.NewRow();
            for (int x = 0; x < table.Rows[i].Cells.Count; x++)
            {
                TextBox valueTextBox = (TextBox)table.Rows[i].Cells[x].Controls[0];
                valueRow[x] = valueTextBox.Text;
            }
            dt.Rows.Add(valueRow);
        }

        return ds;
    }

    public Table DataSetToTable(DataSet ds)
    {
        DataTable dt = ds.Tables["Dimensions"];
        Table newTable = new Table();

        //Add headers
        TableRow headerRow = new TableRow();
        for (int i = 0; i < dt.Columns.Count; i++)
        {
            TableCell headerCell = new TableCell();
            TextBox headerTxtBox = new TextBox();
            headerTxtBox.ID = "HeadersTxtBox" + i.ToString();
            headerTxtBox.Font.Bold = true;
            headerTxtBox.Text = dt.Columns[i].ColumnName;

            headerCell.Controls.Add(headerTxtBox);
            headerRow.Cells.Add(headerCell);
        }
        newTable.Rows.Add(headerRow);

        //Add value rows
        for (int i = 0; i < dt.Rows.Count; i++)
        {
            TableRow valueRow = new TableRow();
            for (int x = 0; x < dt.Columns.Count; x++)
            {
                TableCell valueCell = new TableCell();
                TextBox valueTxtBox = new TextBox();
                valueTxtBox.ID = "ValueTxtBox" + i.ToString() + i + x + x.ToString();
                valueTxtBox.Text = dt.Rows[i][x].ToString();

                valueCell.Controls.Add(valueTxtBox);
                valueRow.Cells.Add(valueCell);
            }
            newTable.Rows.Add(valueRow);
        }

        return newTable;
    }

    public DataSet DefaultDataSet(int rows, int cols)
    {
        DataSet ds = new DataSet();
        DataTable dt = new DataTable("Dimensions");
        ds.Tables.Add(dt);


        DataColumn nameCol = new DataColumn();
        nameCol.Caption = "Name";
        nameCol.ColumnName = "Name";
        nameCol.DataType = System.Type.GetType("System.String");
        dt.Columns.Add(nameCol);

        DataColumn widthCol = new DataColumn();
        widthCol.Caption = "Width";
        widthCol.ColumnName = "Width";
        widthCol.DataType = System.Type.GetType("System.String");
        dt.Columns.Add(widthCol);

        if (cols > 2)
        {
            DataColumn heightCol = new DataColumn();
            heightCol.Caption = "Height";
            heightCol.ColumnName = "Height";
            heightCol.DataType = System.Type.GetType("System.String");
            dt.Columns.Add(heightCol);
        }
        if (cols > 3)
        {
            DataColumn depthCol = new DataColumn();
            depthCol.Caption = "Depth";
            depthCol.ColumnName = "Depth";
            depthCol.DataType = System.Type.GetType("System.String");
            dt.Columns.Add(depthCol);
        }
        if (cols > 4)
        {
            int newColCount = cols - 4;
            for (int i = 0; i < newColCount; i++)
            {
                DataColumn newCol = new DataColumn();
                newCol.Caption = "New " + i.ToString();
                newCol.ColumnName = "New " + i.ToString();
                newCol.DataType = System.Type.GetType("System.String");
                dt.Columns.Add(newCol);
            }
        }

        for (int i = 0; i < rows; i++)
        {
            DataRow newRow = dt.NewRow();
            newRow["Name"] = "Name " + i.ToString();
            newRow["Width"] = "Width " + i.ToString();
            if (cols > 2)
            {
                newRow["Height"] = "Height " + i.ToString();
            }
            if (cols > 3)
            {
                newRow["Depth"] = "Depth " + i.ToString();
            }
            dt.Rows.Add(newRow);
        }
        return ds;
    }

    public DataSet XMLToDataSet(string xml)
    {
        StringReader sr = new StringReader(xml);
        DataSet ds = new DataSet();
        ds.ReadXml(sr);

        return ds;
    }

    public string DataSetToStringXML(DataSet ds)
    {
        XmlDocument _XMLDoc = new XmlDocument();
        _XMLDoc.LoadXml(ds.GetXml());

        StringWriter sw = new StringWriter();
        XmlTextWriter xw = new XmlTextWriter(sw);

        XmlDocument xml = _XMLDoc;
        xml.WriteTo(xw);
        return sw.ToString();
    }

    private int rowCount
    {
        get { return (int)ViewState["rowCount"]; }
        set { ViewState["rowCount"] = value; }
    }
    private int colCount
    {
        get { return (int)ViewState["colCount"]; }
        set { ViewState["colCount"] = value; }
    }

EDIT: Here's my .aspx as well in case you want to try it out in VS.

    <asp:Panel ID="tablePanel" runat="server" CssClass="table-panel" />
    <asp:Label ID="resultsLabel" runat="server" />
    <asp:LinkButton ID="submit" Text="submit" runat="server" onclick="submit_Click" />
    <asp:LinkButton ID="addColumn" Text="Add Column" runat="server" 
        onclick="addColumn_Click" />
    <asp:LinkButton ID="addRow" Text="Add Row" runat="server" onclick="addRow_Click" />

Thanks in advance,

Marko

A: 

move this code:

tablePanel.Controls.Add(DataSetToTable(DefaultDataSet(rowCount, colC....

To the prerender event to make the table bind to its data after the button click fired.

Roger Alsing
As you can see above I'm doing a set of checks before that code is executed. I've moved that entire chunk of code to the Page_PreRender event but the tablePanel is then empty on submit_click.The error is:Specified argument was out of the range of valid values.resultsLabel.Text = Server.HtmlEncode(DataSetToStringXML(TableToDataSet((Table)tablePanel.Controls[0])));
Marko
Any idea why the values aren't there on submit when the controls are created in PreRender, rather than Page_Load?
Marko
+1  A: 

Just as I recommended in this other question, if you'd like some page logic to execute AFTER the buttons' Click event, put that code into the Page_PreRender instead.

You can read more about it here: ASP.NET page life cycle.

EDIT:

After examining your code more closely, I see that you add stuff and create new controls, which is not a good idea in the PreRender event. Instead, put the code into a separate method. In the Page_Load, check if it is a postback and handle the case when it isn't. In the buttons' click evnt, also add a call to that new method. (thus handling the IsPostback == true case)

Venemo
Yes but then on my submitButton_click event the tablePanel is empty thus throwing an index out of range error.
Marko
It's a real catch 22. I moved the method that creates my controls right after the rowCount = rowCount + 1; and colCount = colCount + 1; code, but was experiencing the same issue when tried to submit the values.
Marko
Edited my answer, gave you a new idea.
Venemo
Sorry I'm not sure I follow. I'm already checking if it's a postback and if it isn't, I'm just setting the default values to 2 and 4. In every other case the page should be recreating the controls with the updated values (rowCount and ColCount respectively). How will putting that in a method help?
Marko
The key is calling the method from the buttons' Click event.
Venemo
The problem is that any time I create controls on the Button Click event, they're not available on the subsequent postback (i.e. submit). This is driving me completely nuts.
Marko
Okay, but does it work after clicking the button?
Venemo
Yep I CAN create the controls everytime I assign + 1 to the colCount or rowCount. It works like a charm. But then when I click submit, poof! Paste the c#/ASP.NET code into VS, that's the whole working page and see if you can get it to work. I'm starting to grow white hairs. Gah.
Marko
I've solved the issue but thanks for your effort. I'll give you +1 once my rep goes up.
Marko
Okay, I'm happy you could solve it. :)
Venemo
+1  A: 

OK I've solved the problem by following instructions in this post.

Here's my final code - feel free to use it if you ever need to create dynamic controls based on a counter.

Also I wouldn't mind feedback on the overall coding style, I always appreciate others' input.

protected void Page_Load(object sender, EventArgs e)
    {
        string xmlValue = ""; //To read a value from a database
        if (xmlValue.Length > 0)
        {
            if (!Page.IsPostBack)
            {
                DataSet ds = XMLToDataSet(xmlValue);
                Table dimensionsTable = DataSetToTable(ds);
                tablePanel.Controls.Add(dimensionsTable);

                DataTable dt = ds.Tables["Dimensions"];
                rowCount = dt.Rows.Count;
                colCount = dt.Columns.Count;
            }
            else
            {
                tablePanel.Controls.Add(DataSetToTable(DefaultDataSet(rowCount, colCount)));
            }
        }
        else
        {
            if (!Page.IsPostBack)
            {
                rowCount = 2;
                colCount = 4;
            }
            else
            {
                if (GetPostBackControl(this.Page).ID == "addRow")
                {
                    rowCount = rowCount + 1;
                }
                else if (GetPostBackControl(this.Page).ID == "addColumn")
                {
                    colCount = colCount + 1;
                }
            }
            tablePanel.Controls.Add(DataSetToTable(DefaultDataSet(rowCount, colCount)));
        }
    }

    protected void submit_Click(object sender, EventArgs e)
    {
        resultsLabel.Text = Server.HtmlEncode(DataSetToStringXML(TableToDataSet((Table)tablePanel.Controls[0])));
    }
    protected void addColumn_Click(object sender, EventArgs e)
    {

    }

    protected void addRow_Click(object sender, EventArgs e)
    {

    }

    public DataSet TableToDataSet(Table table)
    {
        DataSet ds = new DataSet();

        DataTable dt = new DataTable("Dimensions");
        ds.Tables.Add(dt);

        //Add headers
        for (int i = 0; i < table.Rows[0].Cells.Count; i++)
        {
            DataColumn col = new DataColumn();
            TextBox headerTxtBox = (TextBox)table.Rows[0].Cells[i].Controls[0];

            col.ColumnName = headerTxtBox.Text;
            col.Caption = headerTxtBox.Text;
            dt.Columns.Add(col);
        }


        for (int i = 0; i < table.Rows.Count; i++)
        {
            DataRow valueRow = dt.NewRow();
            for (int x = 0; x < table.Rows[i].Cells.Count; x++)
            {
                TextBox valueTextBox = (TextBox)table.Rows[i].Cells[x].Controls[0];
                valueRow[x] = valueTextBox.Text;
            }
            dt.Rows.Add(valueRow);
        }

        return ds;
    }

    public Table DataSetToTable(DataSet ds)
    {
        DataTable dt = ds.Tables["Dimensions"];
        Table newTable = new Table();

        //Add headers
        TableRow headerRow = new TableRow();
        for (int i = 0; i < dt.Columns.Count; i++)
        {
            TableCell headerCell = new TableCell();
            TextBox headerTxtBox = new TextBox();
            headerTxtBox.ID = "HeadersTxtBox" + i.ToString();
            headerTxtBox.Font.Bold = true;
            headerTxtBox.Text = dt.Columns[i].ColumnName;

            headerCell.Controls.Add(headerTxtBox);
            headerRow.Cells.Add(headerCell);
        }
        newTable.Rows.Add(headerRow);

        //Add value rows
        for (int i = 0; i < dt.Rows.Count; i++)
        {
            TableRow valueRow = new TableRow();
            for (int x = 0; x < dt.Columns.Count; x++)
            {
                TableCell valueCell = new TableCell();
                TextBox valueTxtBox = new TextBox();
                valueTxtBox.ID = "ValueTxtBox" + i.ToString() + i + x + x.ToString();
                valueTxtBox.Text = dt.Rows[i][x].ToString();

                valueCell.Controls.Add(valueTxtBox);
                valueRow.Cells.Add(valueCell);
            }
            newTable.Rows.Add(valueRow);
        }

        return newTable;
    }

    public DataSet DefaultDataSet(int rows, int cols)
    {
        DataSet ds = new DataSet();
        DataTable dt = new DataTable("Dimensions");
        ds.Tables.Add(dt);


        DataColumn nameCol = new DataColumn();
        nameCol.Caption = "Name";
        nameCol.ColumnName = "Name";
        nameCol.DataType = System.Type.GetType("System.String");
        dt.Columns.Add(nameCol);

        DataColumn widthCol = new DataColumn();
        widthCol.Caption = "Width";
        widthCol.ColumnName = "Width";
        widthCol.DataType = System.Type.GetType("System.String");
        dt.Columns.Add(widthCol);

        if (cols > 2)
        {
            DataColumn heightCol = new DataColumn();
            heightCol.Caption = "Height";
            heightCol.ColumnName = "Height";
            heightCol.DataType = System.Type.GetType("System.String");
            dt.Columns.Add(heightCol);
        }
        if (cols > 3)
        {
            DataColumn depthCol = new DataColumn();
            depthCol.Caption = "Depth";
            depthCol.ColumnName = "Depth";
            depthCol.DataType = System.Type.GetType("System.String");
            dt.Columns.Add(depthCol);
        }
        if (cols > 4)
        {
            int newColCount = cols - 4;
            for (int i = 0; i < newColCount; i++)
            {
                DataColumn newCol = new DataColumn();
                newCol.Caption = "New " + i.ToString();
                newCol.ColumnName = "New " + i.ToString();
                newCol.DataType = System.Type.GetType("System.String");
                dt.Columns.Add(newCol);
            }
        }

        for (int i = 0; i < rows; i++)
        {
            DataRow newRow = dt.NewRow();
            newRow["Name"] = "Name " + i.ToString();
            newRow["Width"] = "Width " + i.ToString();
            if (cols > 2)
            {
                newRow["Height"] = "Height " + i.ToString();
            }
            if (cols > 3)
            {
                newRow["Depth"] = "Depth " + i.ToString();
            }
            dt.Rows.Add(newRow);
        }
        return ds;
    }

    public DataSet XMLToDataSet(string xml)
    {
        StringReader sr = new StringReader(xml);
        DataSet ds = new DataSet();
        ds.ReadXml(sr);

        return ds;
    }

    public string DataSetToStringXML(DataSet ds)
    {
        XmlDocument _XMLDoc = new XmlDocument();
        _XMLDoc.LoadXml(ds.GetXml());

        StringWriter sw = new StringWriter();
        XmlTextWriter xw = new XmlTextWriter(sw);

        XmlDocument xml = _XMLDoc;
        xml.WriteTo(xw);
        return sw.ToString();
    }

    private int rowCount
    {
        get { return (int)ViewState["rowCount"]; }
        set { ViewState["rowCount"] = value; }
    }
    private int colCount
    {
        get { return (int)ViewState["colCount"]; }
        set { ViewState["colCount"] = value; }
    }
    public static Control GetPostBackControl(Page page)
    {
        Control control = null;

        string ctrlname = page.Request.Params.Get("__EVENTTARGET");
        if (ctrlname != null && ctrlname != string.Empty)
        {
            control = page.FindControl(ctrlname);
        }
        else
        {
            foreach (string ctl in page.Request.Form)
            {
                Control c = page.FindControl(ctl);
                if (c is System.Web.UI.WebControls.Button)
                {
                    control = c;
                    break;
                }
            }
        }
        return control;
    }
Marko
This GetPostBackControl is a clever idea.
Venemo
Side note: in this context, the this instance is equal to the this.Page instance. Thus, you could write "if (!IsPostBack)" or "GetPostBackControl(this)". (Your page inherits from the Page class) ;)
Venemo
Yeah thank god I found it as its solved all my problems! Thanks for your help, I've given you +1 for your effort. Marko
Marko