1

I have 2 gridviews. Gridview1, Gridview2. Both have a common field "ID" When I Select the first row in Gridview1 (ID=1), the values for ID=1 from the Gridview2 shows up in the nested area, but the values show in EVERY row of Gridview1. When I get remove the "select", nothing shows from Gridview2. When I open the page, I want Gridview1 showing, and then the nested Gridview2 showing the contents of the individual ID from Gridivew1. I don't want a select to see everything, I just want both tables to show their data.

What I did:

  • Add Gridview1
  • select my columns to show using sql data source
  • edit columns (added some boundfields and a template field to represent Gridview2)
  • edit templates
  • inserted Gridview2 in the template
  • select my columns
  • Where ID = Gridview1's control value of ID (Gridview1.SelectedValue)
  • Set Gridview1's DataKeyNames to ID

Code behind:

public partial class _Webform : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {

    }

    protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
    {
        if (e.Row.RowType == DataControlRowType.DataRow)
        {
            GridView gv2 = (GridView)e.Row.FindControl("GridView2");

            string connString = @"Data Source=SRV\\\SQLEXPRESS;Initial Catalog=Test_Database;Integrated Security=True";
            string query = "select * from dbo.task where PO_ID =" + e.Row.Cells[0].Text;

            SqlConnection conn = new SqlConnection(connString);
            SqlCommand cmd = new SqlCommand(query, conn);
            conn.Open();

            SqlDataAdapter da = new SqlDataAdapter(cmd);
            DataTable dt = new DataTable();
            da.Fill(dt);
            conn.Close();
            da.Dispose();

            gv2.DataSource = dt;
            gv2.DataBind();
        }
    }
}

HTML Markup:

<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="PO_ID" DataSourceID="SqlDataSource1" EnableModelValidation="True">
    <Columns>
        <asp:CommandField ShowSelectButton="True" />
        <asp:BoundField DataField="PO_ID" HeaderText="PO_ID" SortExpression="PO_ID" />
        <asp:BoundField DataField="Username" HeaderText="Username" SortExpression="Username" />
        <asp:BoundField DataField="UserDate" HeaderText="UserDate" SortExpression="UserDate" />
        <asp:BoundField DataField="PO_Note" HeaderText="PO_Note" SortExpression="PO_Note" />
        <asp:BoundField DataField="Invoice_No" HeaderText="Invoice_No" SortExpression="Invoice_No" />
        <asp:TemplateField HeaderText="Tasks">
            <ItemTemplate>
                <asp:GridView ID="GridView2" runat="server" AutoGenerateColumns="False" DataSourceID="SqlDataSource2" EnableModelValidation="True">
                    <Columns>
                        <asp:BoundField DataField="PO_ID" HeaderText="PO_ID" SortExpression="PO_ID" />
                        <asp:BoundField DataField="Username" HeaderText="Username" SortExpression="Username" />
                        <asp:BoundField DataField="UserDate" HeaderText="UserDate" SortExpression="UserDate" />
                        <asp:BoundField DataField="Cost" HeaderText="Cost" SortExpression="Cost" />
                        <asp:BoundField DataField="column1" HeaderText="column1" SortExpression="column1" />
                        <asp:BoundField DataField="Invoice_Date" HeaderText="Invoice_Date" SortExpression="Invoice_Date" />
                        <asp:BoundField DataField="Invoice_No" HeaderText="Invoice_No" SortExpression="Invoice_No" />
                    </Columns>
                </asp:GridView>
                <asp:SqlDataSource ID="SqlDataSource2" runat="server" ConnectionString="<%$ ConnectionStrings:Test_DatabaseConnectionString3 %>" SelectCommand="SELECT [PO_ID], [Username], [UserDate], [Cost], [_Status] AS column1, [Invoice_Date], [Invoice_No] FROM [Task] WHERE ([PO_ID] = @PO_ID)">
                    <SelectParameters>
                        <asp:ControlParameter ControlID="GridView1" Name="PO_ID" PropertyName="SelectedValue" Type="Int32" />
                    </SelectParameters>
                </asp:SqlDataSource>
                <asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:Test_DatabaseConnectionString3 %>" SelectCommand="SELECT [PO_ID], [Username], [UserDate], [Cost], [_Status] AS column1, [Invoice_Date], [Task_Note], [Invoice_No] FROM [Task] WHERE ([PO_ID] = @PO_ID)">
                    <SelectParameters>
                        <asp:ControlParameter ControlID="GridView1" Name="PO_ID" PropertyName="SelectedValue" Type="Int32" />
                    </SelectParameters>
                </asp:SqlDataSource>
            </ItemTemplate>
        </asp:TemplateField>
    </Columns>
</asp:GridView>
<asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:Test_DatabaseConnectionString3 %>" SelectCommand="SELECT [PO_ID], [Username], [UserDate], [PO_Note], [Invoice_No] FROM [PO_Table]"></asp:SqlDataSource>
<br />
j.f.
  • 3,908
  • 2
  • 29
  • 42
Josh M
  • 173
  • 5
  • 17
  • Just to confirm - are both GridViews using SqlDataSources? Is SqlDataSource2 used to populate GridView2? – j.f. Jan 22 '15 at 19:21
  • Yes. SQLDataSource1 --> GridView1 SQLDataSource2 --> Gridview2 – Josh M Jan 22 '15 at 19:26
  • Thanks, and I assume you set the DataSource in the markup like so: `DataSourceID="SqlDataSource2"`? – j.f. Jan 22 '15 at 19:33
  • I edited my original question to add my HTML markup. I'm not sure if there was some confusion. I don't have a stored procedure. I have 2 SQL tables, with a PO_ID as a common field. I just selected my fields using seperate sql data sources ( each using a different table), and included a where clause on datasource 2 to match with PO_ID Gridview.SelectedValue . For example, I have 1 record in the first table with PO_ID=1, and 3 records in the 2nd table with PO=1, so the nested gridview should display 3 records from gridview 1 on PO_ID=1. If your solution still applies, then I'll make one. – Josh M Jan 22 '15 at 19:53
  • Yep, makes sense and my solution still applies. I just assumed you used stored procedures instead of writing out the SQL statements. Just move the SQL statement from SqlDataSource2 into your codebehind, [like so](http://stackoverflow.com/questions/6073382/read-sql-table-into-c-sharp-datatable). Just make sure you aren't exposing yourself to [SQL Injection](http://en.wikipedia.org/wiki/SQL_injection). – j.f. Jan 22 '15 at 20:00
  • @j.f. Something like this? (I edited the code behind above) – Josh M Jan 22 '15 at 20:33
  • Not quite. I edited my answer below. – j.f. Jan 22 '15 at 20:41
  • @j.f. I did what you suggested, made the changes, and it's still only showing gridview1. Is the line that starts "string query = select * from..." right? Because I didn't think a SQL query would end in "=" even followed by a keyword. Should it be an innerjoin statement? The connection string line is what I used for gridview1, but obviously different SQL source code. – Josh M Jan 22 '15 at 21:09
  • Well I assumed `e.Row.Cells[0].Text` resolved to some ID since you had that in your code before, forming a statement that looks more like `select * from dbo.task where PO_ID = 1`. Is that not the case? – j.f. Jan 22 '15 at 21:13
  • @j.f. I had that because I found something like that online and tried using that notation. But yeah, that select statement should give 3 records, from gridview1's ID=1 row. – Josh M Jan 23 '15 at 12:43
  • That seems like it should work. Does it not? When you place a breakpoint after the `query` line, does `query` end up being what it should for each row? – j.f. Jan 23 '15 at 14:04
  • @j.f. Well, first I put a breakpoint in my page_load function at the last paranthesis. When I ran it, nothing showed and referenced the breakpoint. When I clicked "step into", it showed gridview1. I "selected" a row, it stopped me and referenced the breakpoint. I "stepped into" and the row's gridview2's values shows....on every row on gridview1 (same wrong result). So it's populating BEFORE the RowDataBound function. – Josh M Jan 23 '15 at 17:17
  • Well I can tell you that I gave you what I'm pretty sure you need. It sounds like there may be something else going on that I cannot see. It will be very hard for me to help with that. I would recommend looking over different tutorials online. [This one](http://www.codeproject.com/Articles/685079/Nested-GridView-in-ASP-NET-using-Csharp) looks like it contains everything you would need. – j.f. Jan 23 '15 at 17:25
  • @j.f. I appreciate the help you've given. I actually got it working from referencing a different site. http://www.aspsnippets.com/Articles/Collapsible-Nested-GridView-with-Paging-using-ASPNet.aspx If I run into any more issues as I continue, I'll "bug" (get it? hah... *clears throat*) you again. Thanks! – Josh M Jan 23 '15 at 19:00
  • Great, you're welcome! Yep, that is a good example too. It is very similar to what I had suggested but sometimes it's just better to see all of the code written out to be able to tie everything together! Remember to mark answers as accepted if they answer your question. Welcome to StackOverflow! – j.f. Jan 23 '15 at 19:05

1 Answers1

0

Your problem is that you are using one SqlDataSource for multiple GridViews. Since each GridView2 uses SqlDataSource2, they all end up with the same data - the data of the last GridView2 bound. SqlDataSources automatically bind when they are set in the markup like this: DataSourceID="SqlDataSource2".

MSDN on SqlDataSources:

The Select method is automatically called by controls that are bound to the SqlDataSource when their DataBind method is called. If you set the DataSourceID property of a data-bound control, the control automatically binds to data from the data source, as required.

What this means is that when you change the where clause for SqlDataSource2 in GridView1_RowDataBound, all your GridView2s will bind with that new filter.

To fix this, don't use a SqlDataSource for GridView2. Instead, bind them individually, with their own set of data.

protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        GridView gv2 = (GridView)e.Row.FindControl("GridView2");

        string connString = @"your connection string here";
        string query = "select * from dbo.task where PO_ID = " + e.Row.Cells[0].Text;

        SqlConnection conn = new SqlConnection(connString);        
        SqlCommand cmd = new SqlCommand(query, conn);
        conn.Open();

        SqlDataAdapter da = new SqlDataAdapter(cmd);
        DataTable dt = new DataTable();
        da.Fill(dt);
        conn.Close();
        da.Dispose();

        gv2.DataSource = dt;
        gv2.DataBind();
    }
}

Again, I need to stress caution for SQL Injection when doing it this way.

j.f.
  • 3,908
  • 2
  • 29
  • 42