0

I am building a web application to construct a document. The document has paragraphs (outer repeater) and subparagraphs (inner repeater). What I'm looking for is a way to add a blank subparagraph to an existing document.

My markup:

<asp:Repeater ID="ParagraphRepeater" runat="server" 
   OnItemDataBound="ParagraphRepeater_ItemDataBound" >
   <ItemTemplate>
       <asp:TextBox ID="ParagraphTitleTextBox" runat="server" Font-Bold="true" Width="300px" 
           Text='<%# Eval("ParagraphTitle") %>'></asp:TextBox>
       <br />
       <asp:TextBox ID="ParagraphTextTextBox" runat="server" TextMode="MultiLine" Wrap="true"
                        width="1100px" Height="50px" Text='<%# Eval("ParagraphText") %>'></asp:TextBox>
       <asp:Button ID="DeleteParagraphButton" runat="server" Text="Delete" OnClick="DeleteParagraphButton_Click" />
       <asp:Repeater ID="SubParagraphRepeater" runat="server" DataSourceID="SubParagraphSqlDataSource">
           <ItemTemplate>
               <div style="margin-left: 30px">
                   <asp:TextBox ID="SubParagraphTitleTextBox" runat="server" Font-Underline="true" Width="200px"
                                    Text='<%# Eval("SubParagraphTitle") %>'></asp:TextBox>
                   <br />
                   <asp:TextBox ID="SubParagraphTextTextBox" runat="server" TextMode="MultiLine" Wrap="true"
                                    Width="1050px" Height="50px" Text='<%# Eval("SubParagraphText") %>'></asp:TextBox>
                   <asp:Button ID="DeleteSubParagraphButton" runat="server" Text="Delete" 
                                    OnClick="DeleteSubParagraphButton_Click" />
                   <br />
               </div>
           </ItemTemplate>
       </asp:Repeater>
       <br />
       <br />
       <br />
   </ItemTemplate>

My code:

protected void MultiView1_ActiveViewChanged(object sender, EventArgs e)
{
    if (MultiView1.GetActiveView() == InputView) 
    {
        BuildParagraphDataTable();
        BuildSubParagraphDataTable();

        if (RevisionsDropDownList.SelectedValue == "0")
        {
            // User is creating a new document
            // Call method to create a datatable for the form row
            SetFormRow();

            // Call method to create a datatable for the paragraph row
            AddParagraph();

            DataTable dt = (DataTable)ViewState["ParagraphTable"];
            ParagraphRepeater.DataSource = dt;
            ParagraphRepeater.DataBind();

        }
        else
        {
            // User is opening an existing document
            // Get the formId and save it to ViewState
            int formId = Convert.ToInt32(RevisionsDropDownList.SelectedValue);
            ViewState["FormId"] = formId.ToString();

            // Bind the Paragraph repeater to its sqlDataSource
            ParagraphRepeater.DataSource = ParagraphSqlDataSource;
            ParagraphRepeater.DataBind();
        }
    }
}
protected void AddParagraph()
{
    int paragraphId;

    DataTable dt = (DataTable)ViewState["ParagraphTable"];
    DataRow dr = dt.NewRow();

    if (ViewState["ParagraphId"] != null)
        paragraphId = Convert.ToInt32(ViewState["ParagraphId"]);
    else
        paragraphId = 0;

    paragraphId--;

    int formId = Convert.ToInt32(ViewState["FormId"]);

    dr["ParagraphId"] = paragraphId;
    dr["FormId"] = formId;
    dr["ParagraphTitle"] = string.Empty;
    dr["ParagraphText"] = string.Empty;
    dr["CreatorId"] = string.Empty;
    dr["RevisorId"] = string.Empty;
    dt.Rows.Add(dr);

    ViewState["ParagraphTable"] = dt;
    ViewState["ParagraphId"] = paragraphId;

}
protected void AddSubParagraph()
{
    DataTable dt = (DataTable)ViewState["SubParagraphTable"];
    DataRow dr = dt.NewRow();

    int paragraphId = Convert.ToInt32(ViewState["ParagraphId"]);

    dr["ParagraphId"] = paragraphId;
    dr["SubParagraphTitle"] = string.Empty;
    dr["SubParagraphText"] = string.Empty;
    dr["CreatorId"] = string.Empty;
    dr["RevisorId"] = string.Empty;
    dt.Rows.Add(dr);

    ViewState["SubParagraphTable"] = dt;
}

protected void ParagraphRepeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
    if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
    {
        AddParagraph();
        DataTable parentDataTable = (DataTable)ViewState["ParagraphTable"];
        DataRow lastDTRow = parentDataTable.Rows[parentDataTable.Rows.Count - 1];

        int paragraphId = (int)ViewState["ParagraphId"];
        DataRowView thisParagraphRowView = (DataRowView)e.Item.DataItem;

        paragraphId = (int)thisParagraphRowView.Row["ParagraphId"];

        lastDTRow["ParagraphId"] = thisParagraphRowView.Row["ParagraphId"];
        lastDTRow["FormId"] = thisParagraphRowView.Row["FormId"];
        lastDTRow["ParagraphTitle"] = thisParagraphRowView.Row["ParagraphTitle"];
        lastDTRow["ParagraphText"] = thisParagraphRowView.Row["ParagraphText"];

        ViewState["ParagraphTable"] = parentDataTable;
        ViewState["ParagraphId"] = paragraphId.ToString();

        DataTable childDataTable;
        DataRowView thisSubParagraphRowView;

        Repeater childRepeater = (Repeater)e.Item.FindControl("SubParagraphRepeater");

        foreach (RepeaterItem item in childRepeater.Items)
        {
            if (item.ItemType == ListItemType.Item || item.ItemType == ListItemType.AlternatingItem)
            {
                thisSubParagraphRowView = (DataRowView)item.DataItem;
                if (thisSubParagraphRowView != null)
                {
                    AddSubParagraph();
                    childDataTable = (DataTable)ViewState["SubParagraphTable"];
                    lastDTRow = childDataTable.Rows[childDataTable.Rows.Count - 1];

                    lastDTRow["ParagraphId"] = thisSubParagraphRowView.Row["ParagraphId"];
                    lastDTRow["SubParagraphTitle"] = thisSubParagraphRowView.Row["SubParagraphTitle"];
                    lastDTRow["SubParagraphText"] = thisSubParagraphRowView.Row["SubParagraphText"];

                    ViewState["SubParagraphTable"] = childDataTable;
                }
            }
        }
    }
}

When the user opens an existing form, the itemDataBound code populates the datatables for the paragraphs and subparagraphs. (These datatables will be used in the update to the database.)

When the user creates a new form, the setForm() and addParagraph() methods are called to create the form ID and add a blank paragraph. No blank subparagraph is added - the user must click a button to do so.

As for the data model, there is one Form (the user selects it from a ddl). A Form can have 1 to many paragraphs, and paragraphs can have zero to many subparagraphs.

I need to create a blank row in the inner repeater for a particular row in the outer repeater (the paragraph that the cursor is currently located in, or if the cursor is located in a subparagraph, the parent paragraph). How do I do that? I've done a ton of digging on Google but cannot find an entry that addresses this issue. Thanks.

Pete Hesse
  • 45
  • 1
  • 9

1 Answers1

0

The answer is to move the "AddSubParagraph" button from a standalone position to be inside the outer repeater. That way, the repeater can be located by using the "NamingContainer" attribute of the button. Then it's a matter of finding the inner repeater Repeater innerRepeater = (Repeater)outerRepeater.FindControl("childRepeater");, and adding a row to it. I can add the row but I'm having trouble DataBinding the inner repeater.

What I do is keep datatables in viewstate for each repeater, and mirror the data between the repeaters and the datatables. When I need to add a row, I add it to the datatable and then databind the repeater to the datatable. But I get an error: The line it errors on is childRepeater.Datasource = dt;. The error is "DataSource and DataSourceId are both defined. Remove one definition." DataSourceId is defined on the childRepeater in the markup, pointing to a SQLDataSource. So I need to find a way to bind the inner repeater to its SQLDataSource at retrieval time, on the fly.

One snag: I'm thinking I'd use the ItemDataBound event to do the databinding. But I already have a lot of code there (see above). Is there another event I can use that makes sense?

Pete Hesse
  • 45
  • 1
  • 9