Row Count for GridView with paging - asp.net

So I have user controls with GridView tables. I have more tables that are much bigger than this one and have paging enabled, but I'm using this as an example. I want each table to display like this one, where a table with a hundred rows will say "Showing: 1 - 10 of 100" on the first page, "Showing: 11 - 20 of 100" on the second, etc.
This is how it is coded now (in my html file):
<div id="WebsiteHitsMacro">
<umbraco:Macro ID="Macro303" Alias="WebsiteHitsControl" runat="server"></umbraco:Macro>
</div>
<div class="ui-widget-header ui-state-default ui-corner-bl ui-corner-br ui-helper clearfix bottom">
<div class="dataTables_info" id="websitehits_info">Showing: 1-6 of 6</div>
</div>
Here's the ascx code:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataSourceID="SqlDataSource1" CssClass="dataTable" AllowPaging="True"
AllowSorting="True">
<AlternatingRowStyle CssClass="altrow" />
<HeaderStyle CssClass="ui-state-default" />
<Columns>
<asp:BoundField DataField="id" HeaderText="id" SortExpression="id" />
<asp:BoundField DataField="name" HeaderText="name" SortExpression="name" />
</Columns>
</asp:GridView>
I don't know how to get the row count in the first place. Is it possible to have it display in the div I have here?
I hope this makes sense. Thanks.

To get the total amount of rows across all pages of the grid, then use the GridView.Rows, because it represents a collection of all the data rows in your grid. You can use the Count property of that collection, like this:
C#:
int totalRowsCount = GridView1.Rows.Count;
VB.NET:
Dim totalRowsCount As Integer = GridView1.Rows.Count
Now, your problem is that, from what I can see of your posted code, your user control does not expose this information via properties or events that the page can use. I recommend putting this Showing 1-6 of 6 message into the user control itself, so it has component level access to the grid and can easily get the information it needs to display. Either a footer row in the grid or a label that sits right below the actual grid itself.

You said that your Gridview has a paging. By using Dim cnt As Integer = Gridview1.Rows.Count, it only returns the number of rows in Gridview and not the total number of rows the datasource has filtered.
Since you are using SqlDataSource, try this code:
Protected Sub SqlDataSource1_Selected(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.SqlDataSourceStatusEvent Args) Handles
SqlDataSource1.Selected
Dim cnt As Integer = e.AffectedRows
End Sub

Related

Dynamically created Labels and TextBoxes are unable to be positioned

I am building a dynamically created popup window that contains a dynamically created grid and controls (Labels and TextBoxes).
The grid part is working correctly, and not an issue. However, the controls are giving me issues.
The idea is to create a Label and a TextBox for each of the columns in the Grid. I am able to create them fine, but am unable to position them at all. label.Location, label.Top, label.point, etc. return an error saying that it is not part of Label. The same thing happens with the TextBox.
When they do display, they appear in a horizontal row with the TextBox overlapping the Label unless the width is set sufficiently large enough (which of course leave a bunch of empty space).
I would like the to be vertically aligned with the TextBox immediately after the Label.
Something like:
labelText: TextBox
These controls are being added into an asp:Panel (pnlFields)
For Each col As DataColumn In dataTable.Columns
Dim label As New Label()
label.Text = col.ColumnName & ": "
label.Height = 24
label.Width = label.Text.Length()
pnlFields.Controls.Add(label)
Dim textBox As New TextBox()
textBox.Height = 24
textBox.Width = 100
pnlFields.Controls.Add(textBox)
Next
I would like to try to have the Label width be as long as the text it contains instead of static, that way I would (hopefully) be able to set the TextBox location to be right after the Label.
In any event, I can't seem to specify a position at all in order to do this.
Any ideas?
Thanks!
Edit: Markup
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
<asp:Panel runat="server" ID="pnlFields" CssClass="FormStyle" Height="600px" />
<asp:Panel runat="server" ID="pnlFinder" CssClass="FormStyle">
<telerik:RadGrid ID="batchRecords" runat="server" Skin="Windows7" ShowHeader="true" AutoGenerateColumns="true" Width="600px" AutoPostBack="true">
<MasterTableView CommandItemDisplay="Bottom" AllowPaging="true">
<CommandItemSettings ShowAddNewRecordButton="false" />
<Columns>
<telerik:GridButtonColumn UniqueName="selectRecord" HeaderText="Edit" CommandName="Select" Text="Edit Record" ButtonType="ImageButton" ImageUrl="~/images/icons/pencil.png">
</telerik:GridButtonColumn>
</Columns>
</MasterTableView>
</telerik:RadGrid>
</asp:Panel>
</asp:Content>
I really, but really don't see the need for creating those text boxes. there is a LARGE number of built in repeating controls. If you create those controls on the fly, then you can NOT wire up the code behind events - so you quite much give up the WHOLE reason for using asp.net and ALL of those great built in controls.
I see no reason why you can inject and include some extra "divs" and apply style to those divs. But, before you go down that road?
You should attempt to make a VERY STRONG case as to why you going down this road as opposed to using a listview, gridview, or a repeater control. They are designed for repeating data over and over - and do so WITH VERY LITTLE code and VERY LITTLE markup.
and where does the data come from that going to fill out these controls? Or even the reverse - where is the reulsts of the controls going to be placed? You see, by using say a repeater or whatever? They are data bound. So, a person can say add 2 or 15 rows of data, and then in ONE sql update operations you can write out ALL of that data! - in other words, you are repeating some controls - but based on what and how is the big question here?
And as noted, if you create + inject such controls, then you can't have nor wire up events for these controls. So, think very long and hard as to the final goal here. You might fix the layout issues, but then your next issue/problem will be event code, and then after that, will be the complex code required to take that input and somehow push it back out to some database. As a result, I really don't recommend this road.
Further more, using one of those built in "repeating" objects allows you with relative ease to enable editing of that data on screen, and as noted, writing back one row, or 15 rows of data can be done with the same code - and with far greater ease then trying to inject dynamic controls into that form. Furthermore, what "id" are you going to use for referencing those controls and once you managed to inject these controls?
The end goal here is the key concept.
I find that gridview is nice - often less mark up. However WHEN you start to have say 3 or more custom controls in that grid? Then I like listview over that of gridview (because listview allows you to drap + drop and use standard asp.net controls WITHOUT having to put that control inside of a template block. But, your case? Only two extra controls for each row of the grid? then sure, stick with grid view.
So, to add those two extra columns to that grid? You can do this:
First, I will use the wizard to create this gridview. I THEN blow out the data sourceID setting and also chop out the datasource control on the form.
So, I count less then 1 minute - drop gridview. Click on the configure data source from the form. This one:
So I configure the data source, generate the gv, AND THEN remove the data source ID and also remove the data source control from the markup. So, it takes 30 seconds of time, and I wind up with this grid:
So, we get this:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="ID">
<Columns>
<asp:BoundField DataField="ID" HeaderText="ID" InsertVisible="False" ReadOnly="True" SortExpression="ID" />
<asp:BoundField DataField="FirstName" HeaderText="FirstName" SortExpression="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="LastName" SortExpression="LastName" />
<asp:BoundField DataField="HotelName" HeaderText="HotelName" SortExpression="HotelName" />
<asp:BoundField DataField="City" HeaderText="City" SortExpression="City" />
</Columns>
</asp:GridView>
And the code to load this grid up is this:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If IsPostBack = False Then
LoadGrid()
End If
End Sub
Sub LoadGrid()
Using cmdSQL As New SqlCommand("SELECT ID, FirstName, LastName, HotelName, City from tblHotels",
New SqlConnection(My.Settings.TEST3))
cmdSQL.Connection.Open()
GridView1.DataSource = cmdSQL.ExecuteReader
GridView1.DataBind()
End Using
End Sub
And now we have this:
Ok, not bad for less time then it took me to WRITE this post!!!
And note how we only up to about what - 3 lines of code to load up the grid?
Super easy.
Ok, so now lets add a label, and a text box to the grid.
Well, just do this for the gv template:
So, note how we just added two extra columns. The markup is like this:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="ID">
<Columns>
<asp:BoundField DataField="ID" HeaderText="ID" InsertVisible="False" ReadOnly="True" SortExpression="ID" />
<asp:BoundField DataField="FirstName" HeaderText="FirstName" SortExpression="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="LastName" SortExpression="LastName" />
<asp:BoundField DataField="HotelName" HeaderText="HotelName" SortExpression="HotelName" />
<asp:BoundField DataField="City" HeaderText="City" SortExpression="City" />
<asp:TemplateField HeaderText = "My label">
<ItemTemplate>
<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText = "My Text Box">
<ItemTemplate>
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Now, when we run the above, we get this:
I mean was that easy or what? And I could have placed that lable + text box in the SAME TEMPLATE column. So you quite much free to add those extra columns to that grid, and we did not have to write code - and in fact it was VERY easy, and the result is we now have that extra two columns - and achieve this WITH GREAT ease.
And we can also with relative ease set/change the values of the label and text box - even based on other colum data from that row, and can do that again with great ease.
So, at the end of the day? I don't suggest you try and manual add two columns when we have such a great approach as outlined above. and even better, is the values the user types into each row and text box can via code be pulled and refreenced from that gv - and done so with great ease for 2 rows, or 20 rows of data.
Edit:
Since the controls and addtions to the gv are to be at run time (dynamic), then you STILL WANT to use the gv object model - fighting against that model is a REALLY bad idea - go with the flow.
So, you can add extra bound field columns to the gv this way:
Sub LoadGrid()
Using cmdSQL As New SqlCommand("SELECT ID, FirstName, LastName, HotelName, City from tblHotels",
New SqlConnection(My.Settings.TEST3))
cmdSQL.Connection.Open()
GridView1.DataSource = cmdSQL.ExecuteReader
AddColumns()
GridView1.DataBind()
End Using
End Sub
Sub AddColumns()
Dim lblfield As New BoundField()
lblfield.HeaderText = "Label1"
GridView1.Columns.Add(lblfield)
Dim txtfield As New BoundField()
txtfield.HeaderText = "TextBox"
GridView1.Columns.Add(txtfield)
End Sub
And then on item bound event, you can also then inject the controls of your choosing like this:
Protected Sub GridView1_RowDataBound(sender As Object, e As GridViewRowEventArgs) Handles GridView1.RowDataBound
If e.Row.RowType = DataControlRowType.DataRow Then
Dim MyLabel As New Label
MyLabel.ID = "Label1"
MyLabel.Text = "Label Text"
e.Row.Cells(5).Controls.Add(MyLabel)
Dim MyTextBox As New TextBox
MyTextBox.ID = "Textbox1"
MyTextBox.Text = "Text box value"
e.Row.Cells(6).Controls.Add(MyTextBox)
End If
End Sub
so, now with this simple markup:
<link href="Content/cuscosky.css" rel="stylesheet" />
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="ID">
<Columns>
<asp:BoundField DataField="ID" HeaderText="ID" InsertVisible="False" ReadOnly="True" SortExpression="ID" />
<asp:BoundField DataField="FirstName" HeaderText="FirstName" SortExpression="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="LastName" SortExpression="LastName" />
<asp:BoundField DataField="HotelName" HeaderText="HotelName" SortExpression="HotelName" />
<asp:BoundField DataField="City" HeaderText="City" SortExpression="City" />
</Columns>
</asp:GridView>
So, with above code? We get the SAME results, and this output:
Edit:
I solved this by creating an HTML Table in the markup, then programmatically adding Rows and Cells with controls (Labels and TextBoxes) and unique IDs. I was then able to find and populate those controls with the correct data.
Worked MUCH easier than trying to manually position each control.
I was able to solve the issue of positioning the controls.
I needed to use label.Style.Add() and put in the values needeed.
It seems to be working correctly now.
Thanks!

How to use Session to save value on current row of GridView, to be copied into TextBox? - VB.Net

I'm trying to use Session to record the data of the 1st column of current row to be used in another Web From which will be opened using a LinkButton that is in the GridView.
Basically, if I click the LinkButton on the 1st row, the 1st column data of the 1st row will be copied to the next Web Form. But before I do that, I want to do a smaller scale experiment to test it. So instead for now I want the Session to copy the data into a TextBox in the same form.
For reference, here is the design of the GridView, most rows removed since they're not relevant:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
BorderColor="Black" BorderStyle="Solid" BorderWidth="1px" Font-Names="Arial">
<AlternatingRowStyle BackColor="#B7DBFF" />
<Columns>
<asp:BoundField DataField="caseticket" HeaderText="Ticket #" >
<HeaderStyle BackColor="#000066" ForeColor="White" Wrap="False" width="10%"/>
<ItemStyle Wrap="False" />
</asp:BoundField>
<asp:TemplateField ShowHeader="False">
<HeaderStyle BackColor="#000066" ForeColor="White" Wrap="False" width="10%"/>
<ItemTemplate>
<asp:linkbutton ID="newLog" runat="server" onclick = "CaseLog_click" >Add Log </asp:linkbutton>
</ItemTemplate>
</asp:TemplateField>
</Columns>
<HeaderStyle BackColor="#000066" />
<RowStyle HorizontalAlign="Center" />
</asp:GridView>
For the TemplateField is a LinkButton with a onclick property. With it, I created the sub:
Sub CaseLog_click(ByVal sender As Object, ByVal e As EventArgs)
Session("ticket") = GridView1.SelectedRow.Cells(1).Text
'Response.Redirect("~/CaseLog.aspx") ==> will be using this to proceed to next Web Form
TextBox1.Text = Session("ticket") '==> For test use only.
End Sub
If I only kept the Response.Redirect("~/CaseLog.aspx") in the sub, the LinkButton can direct me to the next Web Form. But as it is now, during testing when I use the LinkButton I get an error on the session line of the sub.
Object reference not set to an instance of an object.
Is the code salvageable, or do I need to redo this?
Thanks.
It looks like the button event to select the row is not wired up.
I would use say this:
<asp:BoundField DataField="HotelName" HeaderText="HotelName" SortExpression="HotelName" />
<asp:ButtonField CommandName="Select" HeaderText="Select" ShowHeader="True" Text="Button" />
Note CAREFULL how we put the CommandName="Select" in above. If you don't do this, then the selected row does not come though correctly to the click event you have.
You could try the select command as per above on your link button, but I would just use the above. Now, hightlight the grid in the form desinger. On the properity sheet, go to events, and double click on the SelectedIndex Change event. So, your buttion is not changing the selected index correctly.
The code stub will look like this:
Protected Sub GridView1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles GridView1.SelectedIndexChanged
Dim lgridrow As GridViewRow = Me.GridView1.SelectedRow
Debug.Print("<" & lgridrow.Cells(0).Text & ">")
Debug.Print("<" & lgridrow.Cells(3).Text & ">")
Debug.Print("<" & Me.GridView1.SelectedRow.Cells(3).Text & ">")
End Sub
Note VERY careful how the event code stub is setup - the event args are different then yours.
So, you can try the CommandName="Select" in your existing code, but if not, then try the above button field as opposed to your custom asp.net button you have. As it stands, it don't look like your asp.net button is firing the row-changed event.
Edit and follow up:
Can I have extra buttons - run their own code?
Yes, you can. You can do this several ways (one is to pick up which button was clicked in the SelectedIndex change event.
Or, you can drop in extra buttons and use that event code stub.
So, in my example, lets add an extra button.
we now have this:
<Columns>
<asp:BoundField DataField="ID" HeaderText="ID" InsertVisible="False" ReadOnly="True" SortExpression="ID" />
<asp:BoundField DataField="LastName" HeaderText="LastName" SortExpression="LastName" />
<asp:BoundField DataField="FirstName" HeaderText="FirstName" SortExpression="FirstName" />
<asp:BoundField DataField="HotelName" HeaderText="HotelName" SortExpression="HotelName" />
<asp:ButtonField CommandName="Select" HeaderText="Select" ShowHeader="True" Text="Button" />
<asp:TemplateField>
<ItemTemplate>
<asp:LinkButton ID="LinkButton1" runat="server" OnClick="LinkButton1_Click"
CommandName="MySelect" CommandArgument ="<%# Container.DisplayIndex %>"
style="background-color:gray;color:white;text-decoration:none;padding-left:6px;padding-right:6px"
text="Mybutton"></asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
</Columns>
We thus have this:
Now, we can attach/have button code for the extra button. But NOTE careful we did NOT use the built in SELECT for the command argument. The REASON is that if we have Command=select, then the selected index WILL fire, but AFTER our button code stub. That means we cannot use the selectedrow (too early).
So, what we do/did in above was have the CommandArguemnt PASS the selected row value - that value will pass ok, and thus we don't care that the selected index event does not fire (and by CHANGING our command argument to NOT "select", then in fact the selectedindexchange event DOES NOT fire.
As a result, we use the passed row in the command argument, and we have this for the button code:
Protected Sub LinkButton1_Click(sender As Object, e As EventArgs)
Dim ixrow As Integer = sender.CommandArgument
Debug.Print(Me.GridView1.Rows(ixrow).Cells(0).Text)
End Sub
And note while we are editing the markup, intel-sense will give a list of options when editing. Eg this:
So, that gives us a chance to wire up (add) a standard click event). No selected index code stub is required (since the button would fire before selected index anyway). So we are now manually wiring up this event. We are NOT thus using the selectedindex change event - we don't even need it.
So, now in our button stub, we are free to do anything we want - including jumping to another page
eg:
Protected Sub LinkButton1_Click(sender As Object, e As EventArgs)
Dim ixrow As Integer = sender.CommandArgument
Debug.Print(Me.GridView1.Rows(ixrow).Cells(0).Text)
Session("HotelName") = Me.GridView1.Rows(ixrow).Cells(3)
Response.Redirect("~/ShowHotelDetails.aspx")
End Sub
So, to add separate code buttons:
Don't use selected index change event - you MIGHT still want it to run but it will run/fire AFTER your button code (so can't use selectedrow - too early).
But, you do need Command="myjunk" because without a command, then the command argument does not work. By passing the row index in commandargument, then we are free to grab data from the gridview as per above code via row index.
So, you can well dump the selected index change event. You just have to pass the row index, and work from that. The code stub can thus walk the dog, setup values in session, or even pass/make the url with parameters.

Filter gridview with OnChecked Event

I have a gridview loaded from a database with a checkbox in the first column. What I want is that when clicking on any row the grid will be filtered to show only the rows in which the value of the second cell is the same as the one I clicked on (having the option to select more rows with that value). Removing the checks he would reload all the information again. I tried doing it using the OnChecked event, but due to AutoPostBack it filters but loses the value of the checkbox checked. What is the best way to do what I want? I hope I have been explicit. Thank you
asp:GridView ID="gridview" runat="server" AutoGenerateColumns="false" DataKeyNames="Id">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:CheckBox ID="chkRow" OnCheckedChanged="chkRow_CheckedChanged" AutoPostBack="true" runat="server" />
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="Document" ItemStyle-Width="10%" HeaderText="Documento" />
<asp:BoundField DataField="Entidad" ItemStyle-Width="55%" HeaderText="Entidad" />
</Columns>
For Each row As GridViewRow In gvEncomendasPendentes.Rows
If row.RowType = DataControlRowType.DataRow Then
Dim chkRow As CheckBox = TryCast(row.Cells(0).FindControl("chkRow"), CheckBox)
If chkRow.Checked Then
'Bind with filter
End If
End If
Next
Does the table display the entire dataset at all times? If so, I'd check into client-side filtering (JavaScript). Not having the round trip to the server/database would make your page a lot more responsive.
But assuming that's not the case, and to actually answer the posted question, here's how I'd approach it in the VB.Net Code. Try changing the Change Event like this:
Protected Sub chkRow_CheckedChanged (sender as object, e As EventArgs)
Dim chk As CheckBox = DirectCast(sender, CheckBox)
dim grv As GridRowView = DirectCast(chk.NamingContainer, GridRowView)
dim hdn AS HiddenField = grv.FindControl("hdnFieldWithValue")
If chk.Checked then
AddValueToFilerList(hdn.Value)
Else
RemoveValueFromFilterList(hdn.Value)
End If
BindGridView()
End Sub
Your way does work, but that has a Log(N) time on processing, as it needs to look at every row in the grid. The above way will KNOW which checkbox was checked, and deal with it appropriately.
And this small change to the markup:
<asp:hiddenField runat='server' id='hdnFilterList' />
<asp:GridView ID="gridview" runat="server" AutoGenerateColumns="false" DataKeyNames="Id">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:CheckBox ID="chkRow" OnCheckedChanged="chkRow_CheckedChanged" AutoPostBack="true" runat="server" checked='<%# CheckValueInFilterList(Eval("Entidad")) %>' />
<asp:hiddenField id="hdnFieldWithValue" runat="server" value='<%# Eval("Entidad")' />
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="Document" ItemStyle-Width="10%" HeaderText="Documento" />
<asp:BoundField DataField="Entidad" ItemStyle-Width="55%" HeaderText="Entidad" />
</Columns>
You'll also a function something like this:
Protected Function CheckValueInFilterList(input as string) as boolean
Return MyListOfFilterItems.Contains(input)
End Function
The purpose of that would be to see if the input is contained in your list of filters you're applying to your query and returning true/false depending on that.
Which is directly related to why you're not retaining a check in the checkboxes between postbacks. Since you're rebinding the grid, the existing form state is thrown away in favor of the values from the bind. Since your markup lacked a setter for the checkbox's checked state in the databind, it always resorted to false.
I also added a hidden field to the Markup which would contain the filter list as some type of serialized string (JSON, XML, etc). I'd read it from that field on the Page Load where IsPostBack is True, and always write the list to it in the PreRender event. The point is to just have that passed back and forth through the posted form state so that you can remember them between postbacks.
Maintaining that list of filters in a control outside of the gridview as described does add a bit of overhead in the data that is sent to/from the server on roundtrips. But I wouldn't expect that to a large amount, and would expect a preformance increase due to not having to iterate through the entire gridview item list on every postback.

ASP.NET GridView Linking to another GridView

Ok here is another thing is currently stumping me and I can not seem to find an answer that fits my need. On an aspx page I have a Grid View that gets it data from a SQL query and populates the Grid View, which is working fine. On this grid view though the first column (Column 0) has a line number that was returned from the query. There could one line or 10 or more lines in the grid view data that is returned.
What I am trying to do is add a hyperlink/LinkButton/Button (Not sure which) to the grid view in a column before the line number. I currently have a TemplateField with an asp link button which i can get to show up.
What I can't seem to figure out, and I have been looking for a couple of days now, is how to pull the cell with the line number to pass to my code behind (VB.NET) to have it run a secondary query that will populate another grid view with the line item details.
Here is how I currently have the gridview set up:
<asp:GridView ID="gvDetailSecondLevel" runat="server" AutoGenerateColumns="false" Width="1010px" CellPadding="4" ForeColor="#333333" GridLines="Horizontal" CssClass="SecLvlDtl" OnRowCommand="gvDetailSecondLevel_RowCommand">
<Columns>
<asp:TemplateField ItemStyle-VerticalAlign="Middle">
<ItemTemplate>
<asp:LinkButton ID="btnLineDetail" runat="server" CssClass="dtlButtons" CommandName="Edit" Text="Line Detail" />
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="Line #" HeaderText="Line #" />
<asp:BoundField DataField="Part Desc" HeaderText="Part Description" />
<asp:BoundField DataField="PCS" HeaderText="PCS" />
<asp:BoundField DataField="WT" HeaderText="WT" />
<asp:BoundField DataField="SF" HeaderText="SF" />
</Columns>
The rest of the grid view is formatting so I did not list it for brevity.
The current code behind (Which I am sure is wrong because it throws an error) is as follows:
Protected Sub gvDetailSecondLevel_RowCommand(sender As Object, e As GridViewCommandEventArgs)
'Setup Variables
Dim lineNumber As String = gvDetailSecondLevel.Rows(sender.RowIndex).Cells(0).Text
'Make controls visibile
btnClear.Visible = True
SOThirdLevel.Visible = True
'Retrieve Thrid Level SQL Data
bindThirdLevel(lineNumber)
End Sub
The error that gets thrown says "Public Member 'RowIndex' on type 'GridView' not found"
I should also mention that the second grid view is in a div tag that is on the same page. I am not trying to jump to another apsx page. (I can do that just fine)
So what I need is to figure out how to get the line number cell data passed to the code behind so that I can process it.
Anyone have any thoughts?
Thanks in advance for any help or ideas.
To get your row index, you need to use the GridViewCommandEventArgs object (e). Here is some code to get what you need:
Convert.ToInt32(e.CommandArgument)
Also, cells(0) will give you the cell containing your linkbutton. So, the line that gets the row number will look like this:
Dim lineNumber As String = gvDetailSecondLevel.Rows(Convert.ToInt32(e.CommandArgument)).Cells(1).Text
This is how I finally got it to work.
'Get RowIndex
Dim rowIndex As Integer = Convert.ToInt32(e.CommandArgument)
'Reference Grid View Row
Dim row As GridViewRow = gvDetailSecondLevel.Rows(rowIndex)
'Get Cell value
Dim lineNumber As String = row.Cells(1).Text
I was able to then pass the variable lineNumber to my sub and it works great now!
Thanks Wenadin for the pointer!

Updating a Hybrid DetailsView (with static and dynamic fields)

I've got a DetailsView which has some static fields defined in my markup and adds some extra fields dynamically in the VB codebehind. It should be noted that the DetailsView lives in an UpdatePanel.
Assume that I would like to get inventory information for a number of warehouses, but I only want to see those which have stock on hand. In addition I have some static information such as product, sku, etc.
The problem I was having was that every time I clicked the "Details" button it would just keep appending the dynamic fields to the end and never re-rendering the table. I figure I either need a conditional or to tell it to re-render somehow. I suspect this problem arises from my use of the UpdatePanel but it's important for the user experience of my customer to keep this.
'Warehouse Stock by Location
Dim stockDT As New DataTable
For Each row As DataRow In stockDT.Rows 'Add column for each Warehouse that has stock
'Adds the fields to the DetailsView dynamically for Warehouses with stock.
Dim col As New DataColumn(WarehouseLocID + row(WarehouseLocID).ToString)
Dim bf As New BoundField
bf.HeaderText = "Warehouse " + row(WarehouseLocID)
bf.DataField = col.ColumnName
'NEED HELP HERE! HOW TO UPDATE OR RE-CREATE THE DETAILSVIEW TO REFLECT NEW INFO?
If Not SAPDetailsView.HasControls Then 'BROKEN
SAPDetailsView.Fields.Add(bf)
Else
SAPDetailsView.Fields.Item(0).HeaderText = bf.DataField 'UPDATES THE WRONG "ITEM" FIELD VALUE!!
End If
Next
Here's the very basic markup.
<asp:UpdatePanel ID="statusUpdatePanel" runat="server">
<ContentTemplate>
<asp:GridView ID="ProductsTable" DataSourceID="ProductsSDS">
<Columns>
<asp:ButtonField ButtonType="Button" Text="Details" CommandName="Select" />
</Columns>
</asp:GridView>
<asp:DetailsView ID="WarehouseStock" runat="server" AutoGenerateRows="False">
<Fields>
<asp:BoundField HeaderText="Product" DataField="Product" />
<asp:BoundField HeaderText="Unit Price" DataField="UnitPrice" />
<asp:BoundField HeaderText="SKU" DataField="SKU" />
</Fields>
</asp:DetailsView>
<!-- The Dynamic Fields are appended in the codebehind -->
</ContentTemplate>
</asp:UpdatePanel>
Based on your logic, my guess is that you are not clearing SAPDetailsView prior to updating it with new data. Also note that dynamically added fields usually need to be added in the page_init event in order to survive postback.
If you are just sending the fields to the user and not expecting any data back, then this won't matter, but you also won't get any fields posted back.

Resources