How do I retrieve data from a hidden column in GridView? VB - asp.net

I'm kind of stuck here, after doing some research I can't seem to find an answer. Anyway I don't know how can I retrieve the Primary key in my Gridview hidden column.
Here is my gridview
<asp:GridView ID="grdDent" runat="server" AutoGenerateColumns="False" Width="852px" DataKeyNames="app_id">
<Columns>
<asp:TemplateField>
<EditItemTemplate>
<asp:CheckBox ID="chkApp" runat="server" />
</EditItemTemplate>
<ItemTemplate>
<asp:CheckBox ID="chkApp" runat="server" />
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="app_id" HeaderText="app_id" Visible="False" />
<asp:BoundField DataField="app_date" HeaderText="Date" SortExpression="Date" />
<asp:BoundField DataField="app_time" HeaderText="Time" SortExpression="Time" />
<asp:BoundField DataField="app_rsn" HeaderText="Reason" SortExpression="Reason" />
<asp:BoundField DataField="app_info" HeaderText="Comment" SortExpression="Comment" />
<asp:BoundField DataField="app_sts" HeaderText="Status" SortExpression="Status" />
<asp:BoundField DataField="Patient" HeaderText="Requested by" SortExpression="Patient" />
<asp:BoundField DataField="app_timestamp" HeaderText="Date requested" SortExpression="Date requested" />
</Columns>
</asp:GridView>
And here is my code at button click
For Each row As GridViewRow In grdDent.Rows
If row.RowType = DataControlRowType.DataRow Then
Dim chkApp As CheckBox = TryCast(row.Cells(0).FindControl("chkApp"), CheckBox)
If chkApp.Checked Then
cmd = New MySqlCommand("UPDATE appointment_table SET app_sts = 'Approved' WHERE app_id = #p1", con)
cmd.Parameters.AddWithValue("#p1", row.Cells(1).Text)
con.Open()
cmd.ExecuteNonQuery()
con.Close()
End If
End If
Next
Here is my code to fill up the gridview
Using cmd = New MySqlCommand("SELECT app_id, app_date, app_time, app_rsn, app_info, app_sts, group_concat(pat_lname, pat_fname) As Patient, app_timestamp FROM appointment_table INNER JOIN patient_table WHERE app_sts = 'Queue'", con)
con.Open()
Dim ds As New DataSet()
Dim a As New MySqlDataAdapter(cmd)
a.Fill(ds)
grdDent.DataSource = ds
grdDent.DataBind()
con.Close()
End Using
The problem now is that whenever I click the button, it would not do anything, not even show an error, so I do not know what to do.

First debug the code and check from which line you are getting the error.
Also try following code.
.HideData
{
display: none;
}
Replace your app_id bound field like as below.
Don't use visible false property.

when you set visible=false that column will not rendered in gridview's html.
so, instead of visible=false make its style='display:none'
use like this :
<asp:BoundField DataField="ItemDesc" HeaderText="app_id" >
<ItemStyle CssClass="hidden"/>
</asp:BoundField>
<style type="text/css">
.hidden
{
display:none;
}
</style>
and use this in your foreach loop
dim appid as string
appid=row.Cells(1).Text

I see that you store the primary key in DataKeyNames="app_id"
so you would grab that in code with
grdDent.DataKeys.Item(a row index here).Value
You can drop the BoundField holding this value. It being "Visible=False" will not hold any value.

The way I do it is like this..
1st remove your boundfield and just add a lable to one of the template fields like this.
<asp:GridView ID="grdDent" runat="server" AutoGenerateColumns="False" Width="852px" DataKeyNames="app_id">
<Columns>
<asp:TemplateField>
<EditItemTemplate>
<asp:CheckBox ID="chkApp" runat="server" />
</EditItemTemplate>
<ItemTemplate>
<asp:CheckBox ID="chkApp" runat="server" />
<asp:Label ID="lblApp_ID" Visible="False" runat="server" Text='<%# Bind("app_id") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="app_date" HeaderText="Date" SortExpression="Date" />
<asp:BoundField DataField="app_time" HeaderText="Time" SortExpression="Time" />
<asp:BoundField DataField="app_rsn" HeaderText="Reason" SortExpression="Reason" />
<asp:BoundField DataField="app_info" HeaderText="Comment" SortExpression="Comment" />
<asp:BoundField DataField="app_sts" HeaderText="Status" SortExpression="Status" />
<asp:BoundField DataField="Patient" HeaderText="Requested by" SortExpression="Patient" />
<asp:BoundField DataField="app_timestamp" HeaderText="Date requested" SortExpression="Date requested" />
</Columns>
</asp:GridView>
by doing this it will put the label in each row but it wont show up to the user and the part that says "Text='<%# Bind("app_id") %>'" that binds the text to that label in each row.
Now for the code on the button click you should use this:
Dim i As Integer = 0
Dim app_ID As Integer '<- I was using an integer but you can use any datatype
For Each row As GridViewRow In grdDent.Rows
If CType(row.FindControl("chkApp"), CheckBox).Checked = True Then
app_ID = CType(grdDent.Rows(i).FindControl("lblApp_ID"), Label).Text
cmd = New MySqlCommand("UPDATE appointment_table SET app_sts = 'Approved' WHERE app_id =" & app_ID , con)
con.Open()
cmd.ExecuteNonQuery()
con.Close()
End If
i += 1
Next
All of this has worked for me, so I hope it works for you!

You can use something like this:
For Each row As GridViewRow In yourgrid.Rows
Dim chk As CheckBox = CType(row.FindControl("chkApp"), CheckBox)
If chk IsNot Nothing And chk.Checked Then
'get your selected row data here and perform update operation
End If
Next row
NOTE: My suggestion is to first debug the code and make sure your code is working fine and method is calling perfectly.
You can check getting asp.net gridview selected row data from server-side to get more details.
Hope it helps you!

Related

Kindly help Index was out of range. Must be non-negative

<asp:GridView ID="gvUnitNomRoll" runat="server" OnRowCommand ="gvUnitNomRoll_RowCommand1" SkinID="gridviewSkin" Width="100%"
DataKeyNames="id, name, desig, idr, service" EmptyDataText="" AutoGenerateColumns="false">
<Columns>
<asp:TemplateField HeaderText="Sl" HeaderStyle-HorizontalAlign="Center" ItemStyle-HorizontalAlign="Center">
<ItemTemplate> <%#Ctype (Container, GridViewRow).RowIndex+1 %></ItemTemplate>
</asp:TemplateField>
<asp:BoundField HeaderText="id" DataField="name" Visible ="false"/>
<asp:BoundField HeaderText="Name" DataField="name"/>
<asp:BoundField HeaderText="desig" DataField="desig" />
<asp:BoundField HeaderText="Idr" DataField="idr" />
<asp:BoundField HeaderText="Service" DataField="service" />
<asp:ButtonField ButtonType="Button" CommandName="ed" ControlStyle-CssClass ="allBtn blue" HeaderText="Update Details"
ItemStyle-HorizontalAlign="Center" ItemStyle-Width="80px" Text="Update" />
<asp:ButtonField ButtonType="Button" CommandName="tfrOut" ControlStyle-CssClass ="allBtn red"
HeaderText="Transfer" ItemStyle-HorizontalAlign="Center" ItemStyle-Width="80px" Text="Transfer Out" />
<asp:ButtonField ButtonType="Button" CommandName="Verify" ControlStyle-CssClass ="allBtn green"
HeaderText="Verify" ItemStyle-HorizontalAlign="Center" ItemStyle-Width="80px" Text="Verify" />
</Columns>
</asp:GridView>
this is my vb.code
Dim CmdName As String = e.CommandName
Dim nInt As Integer = Convert.ToInt32(e.CommandArgument)
Dim currentPno As String = gvUnitNomRoll.DataKeys(nInt).Item("id").ToString() 'Here throws error '
If (e.CommandName = "ed") Then
If currentPno <> "" Then
It throws error
Index was out of range. Must be non-negative and less than the size of the collection. Parameter name: index
while debugging
Dim currentPno As String = gvUnitNomRoll.DataKeys(nInt).Item("id").ToString() 'Here throws error '
Lets back the truck here a bit.
first up, there is VERY little reason to stuff up datakeys with all those values. You HAVE those values in the grid, so, no real need to put them again into datakeys.
Datakeys as a genreal rule SHOULD ONLY hold the database primary key "ID".
And daykeys are nice, since THEN you don't have to display/include/have/worry about showing that ID in the GV. (users don't need to see or care). And in fact for security reasons, you don't need nor want to include the database PK id in that gv anyway. (kind of the whole point of datakeys).
Also, I don't see ANYWHERE where you are setting command arument, but you THEN attmept to pull command augrement into a int value (so, that's where your code is failing).
so, in general, if you want a simple button click in the GV?
Then just drop in a plain jane regular button. They work better, are easy to use, and BETTER you do DOUBT in the past worked with a plain jane good old asp.net button.
So, I don't have your data, but lets load up a gv with some rows of data (Hotels). then add a button click to the gv, and then get/enjoy/use/have use of the one data row the user clicked on.
<h3>Hotels</h3>
<asp:GridView ID="GridView1" runat="server" Width="40%"
AutoGenerateColumns="False" DataKeyNames="ID" CssClass="table" >
<Columns>
<asp:BoundField DataField="FirstName" HeaderText="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="LastName" />
<asp:BoundField DataField="HotelName" HeaderText="HotelName" />
<asp:BoundField DataField="City" HeaderText="City" />
<asp:BoundField DataField="Description" HeaderText="Description" />
<asp:TemplateField>
<ItemTemplate>
<asp:Button ID="cmdEdit" runat="server" Text="Edit"
CssClass="btn"
onclick="cmdEdit_Click" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
So, use a "Template" field, and inside of that, you can put ANY standard plane jane asp.net control - including that of a button.
Now, in most cases, when we drag + drop a button into a webform, we can double click on that button to wire up a click event. However, since the button is "nested" inside of the gv, then we can't easy double click on the button, and jump to the code behind stub.
So, in markup view, simple type in onclick=.
When you hit "=", then intel-sense will kick in, and "offer" you to create the simple button click.
it works, looks like this:
so, here is a our gv markup:
<h3>Hotels</h3>
<asp:GridView ID="GridView1" runat="server" Width="40%"
AutoGenerateColumns="False" DataKeyNames="ID" CssClass="table" >
<Columns>
<asp:BoundField DataField="FirstName" HeaderText="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="LastName" />
<asp:BoundField DataField="HotelName" HeaderText="HotelName" />
<asp:BoundField DataField="City" HeaderText="City" />
<asp:BoundField DataField="Description" HeaderText="Description" />
<asp:TemplateField>
<ItemTemplate>
<asp:Button ID="cmdEdit" runat="server" Text="Edit"
CssClass="btn"
OnClick="cmdEdit_Click"
/>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
And our code behind to load the GV is this:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
LoadData()
End If
End Sub
Sub LoadData()
Dim strSQL = "SELECT * FROM tblHotelsA ORDER BY HotelName"
Dim cmdSQL As New SqlCommand(strSQL)
GridView1.DataSource = MyrstP(cmdSQL)
GridView1.DataBind()
End Sub
Ok, so now we need the event code for that button click.
Protected Sub cmdEdit_Click(sender As Object, e As EventArgs)
Dim btn As Button = sender
Dim gRow As GridViewRow = btn.NamingContainer
Dim intPK As Integer = GridView1.DataKeys(gRow.RowIndex).Item("ID")
Dim cmdSQL = New SqlCommand("SELECT * FROM tblHotelsA WHERE ID = #ID")
cmdSQL.Parameters.Add("#ID", SqlDbType.Int).Value = intPK
Dim rstHotel As DataTable = MyrstP(cmdSQL)
Debug.Print($"Row click = {gRow.RowIndex}")
Debug.Print($"Data base PK id (data keys) = {intPK}")
Debug.Print($"Hotel Name from gv = {gRow.Cells(2).Text}")
If rstHotel.Rows.Count > 0 Then
Call EditOne(rstHotel.Rows(0))
End If
End Sub
So, output from above is this:
And clicking on a row button, we get this:
output:
Row click = 5
Data base PK id (data keys) = 3
Hotel Name from gv = Sandman Inn
Of course I have a routine called "Editone". All that does is hide the GV, display a div with standard controls, and some code that fills out the controls.
So, edit one looks like:
Sub EditOne(MyRow As DataRow)
ViewState("PKID") = MyRow("ID")
fLoader(EditRecord, MyRow)
GridView1.Visible = False
EditRecord.Visible = True
End Sub
so, now we see/get this:
"fLoader" is a routine that loops all controls in that div, and shoves in values from the one data row.

How to dynamically assign ID to a checkbox in a for-each cycle

I have the following code in a ascx : I run a SQL query and I put it in a Datatable. Then I show the values in the page like this
<% For each row As DataRow In myDataTable.Rows %>
<%=row("something") %>
<%=row("somethingelse") %>
<asp:CheckBox ID="CheckBox1" runat="server" />
<% next %>
Now... how can I set the ID of the checkbox dynamically?
something like
<asp:CheckBox ID="<%=row("MyId")%>" runat="server" />
that obviously do not work.
I need to set the id as the value I get from the DB so if it is checked I can pass the checked id to another page.
The problem is that row("MyId") returns type of object so you need to convert it to string to be able to bind it to Checkbox
<asp:CheckBox ID="<%=row('MyId').ToString()%>" runat="server" />
See: DataRow.Item[] Property
Hum, would not a data control say like listview, or gridview be better here?
You can have this markup:
<asp:GridView ID="GVHotels" runat="server" class="table" AutoGenerateColumns="false">
<Columns>
<asp:BoundField DataField="FirstName" HeaderText="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="LastName" />
<asp:BoundField DataField="City" HeaderText="City" />
<asp:BoundField DataField="HotelName" HeaderText="HotelName" HeaderStyle-Width="200" />
<asp:BoundField DataField="Description" HeaderText="Description" />
<asp:TemplateField HeaderText="Active" ItemStyle-HorizontalAlign="Center" >
<ItemTemplate>
<asp:CheckBox ID="ckActive" runat="server"
Checked=<%# Eval("Active") %> />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Now to load we have this:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
Dim strSQL As String =
"SELECT TOP 10 FirstName, LastName, HotelName, City, Description, Active
FROM tblHotels WHERE description is not null ORDER BY HotelName"
GVHotels.DataSource = MyRst(strSQL)
GVHotels.DataBind()
End If
End Sub
and we get this:
So, it is a lot less work to do the above.
Even if you don't have a bound check box, you can even feed the grid the data, and display a un-bound check box for selecting rows if that what you need/want.

Show/hide column in gridview based on Role

I have a GridView I populate, and want to show/hide the edit link based on whether the person logged in is either an Admin or User. I am not receiving any errors but cannot figure out why its not working.
aspx
<asp:GridView ID="RepView" runat="server" HeaderStyle-BackColor="#bfbfbf" HeaderStyle-ForeColor="White" HeaderStyle-Font-Underline="true" CellPadding="2" GridLines="None" AutoGenerateColumns="false" Width="990px">
<AlternatingRowStyle BackColor="#DCDCDC" />
<Columns>
<asp:BoundField DataField="Id" HeaderText="Id" />
<asp:BoundField DataField="FirstName" HeaderText="First Name" />
<asp:BoundField DataField="LastName" HeaderText="Last Name" />
<asp:BoundField DataField="EmployeeId" HeaderText="Employee Id" />
<asp:BoundField DataField="Shift" HeaderText="Shift" />
<asp:BoundField DataField="Supervisor" HeaderText="Supervisor" />
<asp:BoundField DataField="Center" HeaderText="Center" />
<asp:BoundField DataField="DateSubmitted" HeaderText="Date Entered" />
<asp:TemplateField ItemStyle-HorizontalAlign="Center" HeaderText="Details">
<ItemTemplate>
Edit
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
code behind
Private Sub BindGrid()
Dim DefaultConnection As String = ConfigurationManager.ConnectionStrings("DefaultConnection").ConnectionString
Using con As New SqlConnection(DefaultConnection)
'This is not working...
If My.User.IsInRole("User") Then
RepView.Columns(9).Visible = False
ElseIf My.User.IsInRole("Admin") Then
RepView.Columns(9).Visible = True
End If
' End of questionable part....
Using cmd As New SqlCommand()
cmd.CommandText = ("SELECT * from Reps")
cmd.Connection = con
con.Open()
RepView.DataSource = cmd.ExecuteReader()
RepView.DataBind()
con.Close()
End Using
End Using
End Sub
Try moving your code behind "Questionable Part" from the Private Sub BindGrid() to The gridview_Load event. My guess is that what's happening is that the gridview is loading, then it gets to your code Private sub BindGrid() to show/hide columns but the columns are already loaded, therefor it can not hide them. It will continue to show the columns even after running through this code unless you run the check and show/hide the columns in the load event.
One other possible solution is that it looks like in the Private Sub BindGrid() you are trying to hide the columns before the query which means the columns will not have been created yet so you have to create the columns first before you can hide and of them. Move the questionable part down below your sql command.
Try something like this...
Protected Sub GridView1_RowDataBound(sender As Object, e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles GridView1.RowDataBound
Dim x As Integer = 0
If x = 0 Then
GridView1.Columns(0).Visible = False
Else
GridView1.Columns(0).Visible = True
End If
End Sub
I have tested this and using x = 0 will hide the first column using x = 1 will show the first column.
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataKeyNames="ID" DataSourceID="SqlDataSource1">
<asp:SqlDataSource ID="SqlDataSource1" runat="server"
ConnectionString="<%$ ConnectionStrings:Sprayer_Parts_CatalogConnectionString %>"
SelectCommand="SELECT [ID], [Order#] AS column1, [Gallon], [Price] FROM [Tanks]">
</asp:SqlDataSource>

Use LINQ with GridView

I am new to web dev and using controls so please forgive me.
I have a GridView with check boxes in it (please see markup below)
When a user goes through and checks any boxes and hits my submit button
I want to run LINQ query to get all the rows with the checkbox1.checked = True
Something like:
Dim sList = (From row in Gridview1
Where row.Cells("IsStarFleet") = True
row.Cells("ID)).ToList
Markup:
<asp:GridView ID="GridView1" runat="server" Width="516px" AutoGenerateColumns="False" AllowPaging="True">
<Columns>
<asp:BoundField DataField="ID" HeaderText="ID" />
<asp:BoundField DataField="FirstName" HeaderText="FirstName" />
<asp:TemplateField HeaderText="IsStarFleet">
<ItemTemplate>
<asp:CheckBox ID="CheckBox1" runat="server" AutoPostBack ="False" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
You need to use FindControl for controls in a TemplateField and Cells(index) for BoundFields:
Dim checkedIDs = From row In GridView1.Rows.Cast(Of GridViewRow)()
Where DirectCast(row.FindControl("CheckBox1"), CheckBox).Checked
Select row.Cells(0).Text
Dim checkedIdList = checkedIDs.ToList()

Problems making LinkButton visible in certain rows only within a GridView

I have set up a GridView as set out below. You can see there are four LinkButton's per row. What I want to do is make certain LinkButtons available depending on which row they appear in.
<asp:GridView ID="FormsGrid" runat="server" Width="657px" Height="250px" DataKeyNames="FORM_NAME,FORM_ACCESS,STATUS,ID"
AutoGenerateColumns="False" DataSourceID="SqlDataSource1" >
<Columns>
<asp:BoundField DataField="DEADLINE_DATE" HeaderText="Date" DataFormatString="{0:d}"
SortExpression="DEADLINE_DATE" />
<asp:BoundField DataField="FORM_NAME" HeaderText="Event"
SortExpression="FORM_NAME" >
<ItemStyle Width="240px" />
</asp:BoundField>
<asp:BoundField DataField="COMPULSORY" HeaderText="Compulsory?"
SortExpression="COMPULSORY" />
<asp:BoundField DataField="FORM_NO" HeaderText="Form"
SortExpression="FORM_NO" />
<asp:TemplateField HeaderText="Access">
<ItemTemplate>
<asp:LinkButton ID="FormLinkBtn" runat="server"
onclick="FormLinkBtn_Click">Form Link</asp:LinkButton>
<br />
<asp:LinkButton ID="NotReqBtn" runat="server"
onclick="NotReqBtn_Click">Not Required</asp:LinkButton>
<br />
<asp:LinkButton ID="DnLoadBtn" runat="server"
onclick="DnLoadBtn_Click">Download Pdf</asp:LinkButton>
<br />
<asp:LinkButton ID="UploadBtn" runat="server"
onclick="UploadBtn_Click">Upload Pdf</asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="STATUS" HeaderText="Completed?"
SortExpression="STATUS" />
<asp:BoundField DataField="ID" HeaderText="ID" SortExpression="ID" Visible="False" />
</Columns>
</asp:GridView>
When I try to make them not visible use the code below in FormsGrid_RowDataBound, it doesn't work and a get a null value error.
if e.Row.Cells(4).Text = "1" then
Dim FLbtn As LinkButton = FormsGrid.FindControl("FormLinkBtn")
FLbtn.Visible = True
Dim NRbtn As LinkButton = FormsGrid.FindControl("NotReqBtn")
NRbtn.Visible = False
Dim DLbtn As LinkButton = FormsGrid.FindControl("DnLoadBtn")
DLbtn.Visible = False
Dim ULbtn As LinkButton = FormsGrid.FindControl("UploadBtn")
ULbtn.Visible = False
end if
Also when I click say the FormLinkBtn, how do I determine the value of the fields in that particualr row?
Suggestion #1:
wrap your "if" statement in an "if" that checks for a row type:
if (e.Row.RowType == DataControlRowType.DataRow)
{
......// your code here
}
You getting null value exception becuase first you hit the header row. There are few types of rows.
You are only interested in DataRow in this case.
On question part 2:
if you go with just a link buttons and click events you will need to pass some data in CommandArgument or CommandName properties of the linkButton. You can use CommandField or ButtonField instead to avoid dealing with passing data identifying the row in CommandArgument or CommandName.

Resources