I've come across this strange error and it's been bugging me for hours now.
I've got some LinkButtons on my screen and depending on which button the user chooses a label's text is set, a GridView is displayed and the Datasource of this GridView is assigned based on the text of the label.
This all works fine and dandy. However the problem arises when I want to sort this GridView.
At the moment, nothing happens. When I attempt to sort a column the page just refreshes and I'm left with the same unsorted mess in my GridView.
I've put my application into debug mode with breakpoints along the way and noticed that when I get to this step (the full code can be seen at the bottom of this post) :
senderGridView.SortExpression = button.CommandArgument
the senderGridView.SortExpression is "" so for some reason it's not passing the sort expression.
Hopefully somebody can enlighten me as to why my grid isn't sorting as I'm sure it's just a stupid mistake somewhere but any help would be appreciated, thanks.
Code that you may require...
My sub that sets the sort images when a row is created can be seen below:
Protected Sub GridViewSortImages(ByVal sender As Object, ByVal e As GridViewRowEventArgs)
Dim senderGridView As GridView = CType(sender, GridView)
'Loop through each cell in header row
For Each cell As TableCell In e.Row.Cells
If cell.HasControls Then
Dim button As LinkButton = TryCast((cell.Controls(0)), LinkButton)
Dim gv As New HtmlGenericControl("div")
Dim lnkName As New Label()
'Test cell to see if a link button exists (i.e. Allow Sorting = True)
If Not (button Is Nothing) Then
'Create new label and image and set to standard unsorted view
lnkName.Text = button.Text
Dim image As New System.Web.UI.WebControls.Image
image.ImageUrl = "images/sort-1x1.png"
image.ToolTip = "Sort"
image.AlternateText = "Sort"
'Test to see if grid is already sorted, and apply relevant image & tooltip
If senderGridView.SortExpression = button.CommandArgument Then
If senderGridView.SortDirection = SortDirection.Ascending Then
image.ImageUrl = "images/sort-asc.png"
image.ToolTip = "Sort Descending"
image.AlternateText = "Sort Descending"
Else
image.ImageUrl = "images/sort-desc.png"
image.ToolTip = "Sort Ascending"
image.AlternateText = "Sort Ascending"
End If
End If
'Add label and image to new div
gv.Controls.Add(lnkName)
gv.Controls.Add(image)
'Replace original column header with new div
button.Controls.Add(gv)
End If
End If
Next
End Sub
My RowCreated sub for the GridView...
Protected Sub grvHomeRisk_RowCreated(sender As Object, e As GridViewRowEventArgs) Handles grvHomeRisk.RowCreated
If Not (e.Row Is Nothing) AndAlso e.Row.RowType = DataControlRowType.Header Then
GridViewSortImages(sender, e) 'Call sort code
End If
End Sub
My Sorting sub...
Protected Sub grvHomeRisk_Sorting(sender As Object, e As GridViewSortEventArgs) Handles grvHomeRisk.Sorting
Select Case lblBreachHeaderb.Text
Case "Current Risks"
grvHomeRisk.DataSource = SQLDS_ListCurrentRisk
Case "All Risks Overdue"
grvHomeRisk.DataSource = SQLDS_ListAllRiskOverdue
Case "My Risks"
grvHomeRisk.DataSource = SQLDS_ListMyRisk
Case "My Risks Overdue"
grvHomeRisk.DataSource = SQLDS_ListRiskOverdue
Case "Risks Requested to Score & Re-Score"
grvHomeRisk.DataSource = SQLDS_ListScores
Case "Risks Requested to Score"
grvHomeRisk.DataSource = SQLDS_ListRiskScores
Case "Risks Requested to Re-Score"
grvHomeRisk.DataSource = SQLDS_ListRiskReScores
End Select
grvHomeRisk.DataBind()
End Sub
My GridView...
<asp:GridView ID="grvHomeRisk" runat="server" AutoGenerateColumns="false" AllowSorting="true"
CssClass="GridMain" UseAccessibleHeader="false"
ForeColor="#333333" GridLines="None" Width="780px" BorderWidth="0px"
AllowPaging="true" PageSize="5" CellPadding="3" DataKeyNames="IDRISK">
<Columns>
<asp:CommandField ButtonType="Image" SelectText="View Risk" ShowSelectButton="True" SelectImageUrl="~/Images/button-select1.png" />
<asp:BoundField DataField="TXRISKSUMMARY" HeaderText="Risk" ReadOnly="True" />
<asp:BoundField DataField="TSRISKSTART" HeaderText="Start Date" ReadOnly="True" DataFormatString="{0:dd MMM yyyy}" />
<asp:BoundField DataField="TSRISKREVIEW" HeaderText="Review Date" SortExpression="TSRISKREVIEW" ReadOnly="True" DataFormatString="{0:dd MMM yyyy}" />
<asp:BoundField DataField="TXUSER_NAME_O" HeaderText="Owner" SortExpression="TXUSER_NAME_O" ReadOnly="True" />
<asp:BoundField DataField="TXDESCRIPTION" HeaderText="Risk Element" SortExpression="TXDESCRIPTION" ReadOnly="True" />
<asp:BoundField DataField="TSDATMOD" HeaderText="Date Modified" ReadOnly="True" DataFormatString="{0:dd MMM yyyy}" />
<asp:BoundField DataField="TXUSER_NAME_M" HeaderText="Modified By" ReadOnly="True" />
</Columns>
<PagerTemplate>
<table>
<tr>
<td>
<asp:Button ID="FirstButton" runat="server" CommandArgument="First" CommandName="Page" Text="<<" CssClass="buttongrid" ToolTip="First" OnClientClick="needToConfirm = false;" />
<asp:Button ID="PrevButton" runat="server" CommandArgument="Prev" CommandName="Page" Text="Previous" CssClass="button" ToolTip="Previous" OnClientClick="needToConfirm = false;" />
</td>
<td>
<asp:Label ID="lblPageCount" runat="server" CssClass="TextA12Bold" Visible="false"></asp:Label>
</td>
<td>
<asp:Button ID="NextButton" runat="server" CommandArgument="Next" CommandName="Page" Text="Next" CssClass="button" ToolTip="Next" OnClientClick="needToConfirm = false;" />
<asp:Button ID="LastButton" runat="server" CommandArgument="Last" CommandName="Page" Text=">>" CssClass="buttongrid" ToolTip="Last" OnClientClick="needToConfirm = false;" />
</td>
</tr>
</table>
</PagerTemplate>
</asp:GridView>
Related
I have a drop down list 'Country', 'city' text box and an 'Add' button. The country drop down is NOT mandatory so I can just add a city without a country, adding an empty 'country' to the gridview works OK. the problem when I click on 'Edit' in the gridview it binds it to the first country in the list it does not just show a blank:
<asp:DropDownList ID="DDLCountry" runat="server" AutoPostBack="true" AppendDataBoundItems="true" OnSelectedIndexChanged="DDLCountry_SelectedIndexChanged" InitialValue="">
<asp:ListItem Text="------------------------ Select ------------------------" Value="" />
</asp:DropDownList>
<asp:TextBox ID="txtCity" runat="server"></asp:TextBox>
<asp:Button ID="btnNewLList" runat="server" OnClick="btnNewLList_Click" Text="Add new Country"/>
<asp:GridView ID="gvAddNewCountry" runat="server" AutoGenerateColumns="False" DataKeyNames="ID" OnRowCommand="gvAddNewCountry_RowCommand" OnRowDeleting="gvAddNewCountry_RowDeleting" OnRowDataBound="gvAddNewCountry_RowDataBound" OnRowUpdating="gvAddNewCountry_RowUpdating" OnRowEditing="gvAddNewCountry_RowEditing" OnRowCancelingEdit="gvAddNewCountry_RowCancelingEdit" ShowHeaderWhenEmpty="True">
<EmptyDataTemplate>
No Data
</EmptyDataTemplate>
<Columns>
<asp:TemplateField HeaderText="Actions">
<ItemTemplate>
<asp:Button ID="btnEdit" runat="server" Text="Edit"/>
</ItemTemplate>
</asp:TemplateField>
<asp:CommandField ButtonType="Button" ShowEditButton="true" ShowCancelButton="true">
</asp:CommandField>
<asp:TemplateField HeaderText="Country>
<ItemTemplate>
<asp:Label ID="lblCountry" runat="server" Text='<% #Eval("Country") %>'></asp:Label>
</ItemTemplate>
<EditItemTemplate>
<asp:DropDownList ID="DDCountry" runat="server" AppendDataBoundItems="True" AutoPostBack="false"></asp:DropDownList>
</EditItemTemplate>
</asp:TemplateField>
Code behind:
Protected Sub gvAddNewCountry_RowCommand(sender As Object, e As GridViewCommandEventArgs)
If e.CommandName = "Edit" Then
Dim rowCountryToEdit As Integer = e.CommandArgument
Dim ddListCountry As DropDownList = (CType(gvAddNewCountry.Rows(CInt(e.CommandArgument)).FindControl("DDCountry"), DropDownList))
ddListCountry.DataSource = (From x In Country Where x.Domain = "lCountry" Order By x.Description Select x).ToList()
ddListCountry.DataTextField = "Description"
ddListCountry.DataValueField = "ID"
ddListCountry.DataBind()
End If
End Sub
Thanks for your help X
Ok, so when you have/want a ddl in a gv row?
We require TWO steps.
First step: Load up the list of choices for the dll
2nd step: set the ddl to the current row value, or blank (no choice) if null no value exists yet for the current row. This ALSO means we have to get/grab the current row value for the dll, and set the ddl to reflect this existing choice.
So, this is a two step process.
And the "event" we typical use for this is the row bind event. (all such controls from listview, gridview and more have this event).
Also, a VERY nice helper tip? During (but ONLY during) the data bind event, you have FULL USE of ALL columns from the data source - EVEN COLUMNS NOT in the gv!!!
I don't have a entity database first setup that you have, but lets load up a gv with a combo box:
So, our gv:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
CssClass="table table-hover" Width="50%"
DataKeyNames="ID">
<Columns>
<asp:BoundField DataField="FirstName" HeaderText="First Name" />
<asp:BoundField DataField="LastName" HeaderText="First Name" />
<asp:BoundField DataField="HotelName" HeaderText="Hotel Name" />
<asp:BoundField DataField="City" HeaderText="City" />
<asp:BoundField DataField="Description" HeaderText="Descripiton" />
<asp:TemplateField HeaderText="Rating">
<ItemTemplate>
<asp:DropDownList ID="cboRating" runat="server"
DataTextField="Rating"
DataValueField="ID">
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
And our code to fill is this:
Dim rstRating As New DataTable
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
LoadGrid()
End If
End Sub
Sub LoadGrid()
' get data for rating combo
rstRating = MyRst("SELECT ID, Rating FROM tblRating ORDER BY ID")
' get data for grid
GridView1.DataSource = MyRst("SELECT * FROM tblHotelsA ORDER BY HotelName")
GridView1.DataBind()
End Sub
Public Function MyRst(strSQL As String) As DataTable
Dim rstData As New DataTable
Using conn As New SqlConnection(My.Settings.TEST4)
Using cmdSQL As New SqlCommand(strSQL, conn)
conn.Open()
rstData.Load(cmdSQL.ExecuteReader)
End Using
End Using
Return rstData
End Function
Note VERY carefull in above, I created a page wide (class wide) data table called rstRating. This will go out of scope after the data bind, but we ONLY need it to persit DURING the gv data bind operating (since for each row of the gv, we don't want to run that query over and over - we need this same pick list for the dll).
Ok, so now we see/get this:
The only part we need is to load up the dll, and set it for each row. We use the RowDataBound event.
So, code for that was this:
Protected Sub GridView1_RowDataBound(sender As Object, e As GridViewRowEventArgs) Handles GridView1.RowDataBound
' bind drop down for each row
If e.Row.RowType = DataControlRowType.DataRow Then
' get combo
Dim rDrop As DropDownList = e.Row.FindControl("cboRating")
rDrop.DataSource = rstRating
rDrop.DataBind()
rDrop.Items.Insert(0, New ListItem("Please Select", "0"))
' now get current row value for rating.
Dim gData As DataRowView = e.Row.DataItem
If IsDBNull(gData("Rating")) = False Then
rDrop.Text = gData("Rating")
End If
End If
End Sub
So, for each row, get the dll.
For for that row, load up with choices
And THEN for that row, set the ddl to the current row value (but check for null, and don't set - it will then show our "select" choice value.
as the title states I am trying to filter a grid view based on one or multiple selections made among 4 drop down lists. On a button click event I populate the grid view with the broadest set of information. From here I would like to have the grid view update as I make selections in the available drop down lists (4 in total).
While I feel like I could accomplish this through a series of if statements and a modified query for each condition, I feel like there should be a more efficient way this can be done. Below I have posted any pertinent code to this problem I am having.
html/asp code
<tr>
<td>
<asp:DropDownList ID="ddlSearchOCFamily" AutoPostBack="True" AppendDataBoundItems="True" DataTextField="FamilyLong" DataValueField="FamilyLong" runat="server"></asp:DropDownList>
</td>
<td>
<asp:DropDownList ID="ddlSearchOCRate" AutoPostBack="True" AppendDataBoundItems="True" DataTextField="RateLong" DataValueField="RateLong" runat="server"></asp:DropDownList>
</td>
<td>
<asp:DropDownList ID="ddlSearchOCTerm" AutoPostBack="True" AppendDataBoundItems="True" DataTextField="TermLong" DataValueField="TermLong" runat="server"></asp:DropDownList>
</td>
<td>
<asp:DropDownList ID="ddlSearchOCEnrollment" AutoPostBack="True" AppendDataBoundItems="True" DataTextField="TypeDescription" DataValueField="TypeDescription" runat="server"></asp:DropDownList>
</td>
</tr>
<tr>
<td>
<div style="overflow: auto; width: 100%; padding: 2px;">
<asp:GridView ID="gvReverseSearchOC" runat="server" Width="99%" BackColor="White" BorderColor="#CC9966" BorderStyle="None"
BorderWidth="1px" CellPadding="4" AutoGenerateColumns="False" PageSize="20" AutoGenerateSelectButton="True">
<FooterStyle BackColor="#FFFFCC" ForeColor="#330099" />
<HeaderStyle BackColor="#990000" Font-Bold="True" ForeColor="#FFFFCC" />
<PagerStyle BackColor="#FFFFCC" ForeColor="#330099" HorizontalAlign="Center" />
<RowStyle BackColor="White" ForeColor="#330099" />
<SelectedRowStyle BackColor="#FFCC66" Font-Bold="True" ForeColor="#663399" />
<SortedAscendingCellStyle BackColor="#FEFCEB" />
<SortedAscendingHeaderStyle BackColor="#AF0101" />
<SortedDescendingCellStyle BackColor="#F6F0C0" />
<SortedDescendingHeaderStyle BackColor="#7E0000" />
<Columns>
<asp:BoundField DataField="OrderCode" HeaderText="Order Code" SortExpression="OrderCode" Visible="True" ReadOnly="True" HeaderStyle-Wrap="False" />
<asp:BoundField DataField="Description" HeaderText="Description" SortExpression="Description" ItemStyle-Wrap="False" />
<asp:BoundField DataField="Net Price" HeaderText="Net Price" SortExpression="Net Price" HeaderStyle-Wrap="False" />
</Columns>
</asp:GridView>
</div>
</td>
</tr>
page load event
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
Dim RSQuery As String = "
SELECT dDown.OrderCode, dDown.[Description], dDown.[Net Price]
FROM (
SELECT SKU.OrderCode AS OrderCode, SKU.[Description] AS [Description],
(SELECT FORMAT(SKU.ListPrice * EnrollmentType.Multiplier, 'C')) AS [Net Price]
FROM Enrollment
INNER JOIN EnrollmentType ON Enrollment.EnrollmentTypeID = EnrollmentType.RecID
INNER JOIN SKU ON EnrollmentType.TypeID = SKU.EnrollmentTypeID
INNER JOIN SKUBuild ON SKU.SKU = SKUBuild.SKU
WHERE (Enrollment.AccountNumber = '12345')
AND (Enrollment.Active = 'yes')
AND (SKU.[Description] IS NOT NULL AND NOT (SKU.[Description] = '""'))
) AS dDown
"
pnlSearchOC.Visible = False
PopSearchOCDDLs()
PopGVSearchOC(RSQuery)
End Sub
Procedure to populate the gridview
Protected Sub PopGVSearchOC(ByVal query As String)
Dim dt As New DataTable
Using con As New SqlConnection(ConfigurationManager.ConnectionStrings("WarrantyConnectionString").ToString)
Using cmd As New SqlCommand(query, con)
con.Open()
Using sdr As SqlDataReader = cmd.ExecuteReader
If sdr.HasRows Then
dt.Load(sdr)
With gvReverseSearchOC
.DataSource = dt
.DataBind()
con.Close()
End With
End If
End Using
End Using
If con.State <> ConnectionState.Closed Then
con.Close()
End If
End Using
End Sub
I have one more procedure that populates the drop down lists but I don't believe it is relevant to my problem, I may be wrong.
I am looking for an elegant solution to update/filter my grid view based on the selections made in the drop down lists, any information in this regard would be much appreciated. If I am missing any necessary code I would be happy to supply it but I am pretty sure its all here.
Thanks for you time guys.
Ok, you can do this two ways.
You can pull the data table, and persist the table (but, this can be a bit heavy on browser memory. (but, you could use session() to hold that resulting table - but using session() often means that if the user opens two copies of the page, then things don't work well.
So, probably best to filer against the sql you have. (I would put that sql in a sql server view - we really don't want all sql code in-line, as it hard to maintain.
So, our lodgic:
No selections - show all data. Select 1, or 2 or 3 or 4 combo or filters, then we progressive add this extra conditions. So, blank = ignore, and some value = filter with given values.
So, we kind of need a code stub and approach that works for 1, or 10 filer options. In other words, if we don't find a easy way to "add up" the filters, then we have to write code that considers all combinations. (very bad).
and in this solution, we ALSO very much do NOT want to concatenate values into the sql, since that opens up to not only sql injection, but such code tends to get very messy in a hurry.
So, this approach:
Test the given filter control - if value, then add to our criteria, but STILL use correct parameters - no concatenation of USER input values ever!!!
I don't have your data, but lets just cook up a simple grid, and add a few filters. We will have 2 combo, and say one check box (for only Active Hotels).
So, we have this markup, nothing fancy:
<h4>Filters</h4>
<div style="float:left">
<asp:Label ID="Label1" runat="server" Text="Select City"></asp:Label>
<br />
<asp:DropDownList ID="cboCity" runat="server" Width="180px"
DataValueField="City"
DataTextField="City" >
</asp:DropDownList>
</div>
<div style="float:left;margin-left:20px">
<asp:Label ID="Label2" runat="server" Text="Select Province"></asp:Label>
<br />
<asp:DropDownList ID="cboProvince" runat="server" Width="180px"
DataValueField="Province"
DataTextField="Province" >
</asp:DropDownList>
</div>
<div style="float:left;margin-left:20px">
<asp:Label ID="Label3" runat="server" Text="Must Have Description"></asp:Label>
<br />
<asp:CheckBox ID="chkDescripiton" runat="server" />
</div>
<div style="float:left;margin-left:20px">
<asp:Label ID="Label4" runat="server" Text="Show only Active Hotels"></asp:Label>
<br />
<asp:CheckBox ID="chkActiveOnly" runat="server" />
</div>
<div style="float:left;margin-left:20px">
<asp:Button ID="cmdSearch" runat="server" Text="Search" CssClass="btn"/>
</div>
<div style="float:left;margin-left:20px">
<asp:Button ID="cmdClear" runat="server" Text="Clear Fitler" CssClass="btn"/>
</div>
<div style="clear:both">
<%-- this starts new line for grid --%>
</div>
<asp:GridView ID="GridView1" runat="server"
AutoGenerateColumns="False" DataKeyNames="ID" CssClass="table" Width="60%">
<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="Province" HeaderText="Province" />
<asp:BoundField DataField="Description" HeaderText="Description" />
<asp:BoundField DataField="Active" HeaderText="Active" />
</Columns>
</asp:GridView>
So, we just drop in as many "divs", float them left for the filers. You can easy add more filter controls.
So, now our code to load up this stuff, is say this:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
LoadCombos()
Dim cmdSQL As New SqlCommand("SELECT * FROM tblHotels ORDER BY HotelName")
LoadGrid(cmdSQL)
End If
End Sub
Sub LoadCombos()
Dim cmdSQL As New _
SqlCommand("SELECT City FROM tblHotels WHERE City is not null GROUP by City")
cboCity.DataSource = MyrstP(cmdSQL)
cboCity.DataBind()
cboCity.Items.Insert(0, New ListItem("All", "All"))
cmdSQL.CommandText =
"SELECT Province FROM tblHotels WHERE Province is not null GROUP by Province"
cboProvince.DataSource = MyrstP(cmdSQL)
cboProvince.DataBind()
cboProvince.Items.Insert(0, New ListItem("All", "All"))
End Sub
Sub LoadGrid(cmdSQL As SqlCommand)
Dim rstData As DataTable = MyrstP(cmdSQL)
GridView1.DataSource = rstData
GridView1.DataBind()
End Sub
Public Function MyrstP(sqlCmd As SqlCommand) As DataTable
Dim rstData As New DataTable
Using sqlCmd
sqlCmd.Connection = New SqlConnection(My.Settings.TEST4)
sqlCmd.Connection.Open()
rstData.Load(sqlCmd.ExecuteReader)
End Using
Return rstData
End Function
Again, quite simple - just some clean code to load up our combo, and the grid.
So, now we have this:
Ok, so now the filter code. As noted, this can work if we have 2 or 20 filters. and you can add more over time - you don't have to change EXISTING code.
So, the code is like this - search button:
Protected Sub cmdSearch_Click(sender As Object, e As EventArgs) Handles cmdSearch.Click
Dim strSQL As String = "SELECT * FROM tblHotels"
Dim strOrderBy As String = " ORDER BY HotelName"
Dim strWhere As String = ""
Dim cmdSQL As New SqlCommand("")
If cboCity.Text <> "All" Then
' city filter
strWhere = "(City = #City)"
cmdSQL.Parameters.Add("#City", SqlDbType.NVarChar).Value = cboCity.Text
End If
If cboProvince.Text <> "All" Then
If strWhere <> "" Then strWhere &= " AND "
strWhere &= " (Province = #Province)"
cmdSQL.Parameters.Add("#Province", SqlDbType.NVarChar).Value = cboProvince.Text
End If
' must have description
If chkDescripiton.Checked Then
If strWhere <> "" Then strWhere &= " AND "
strWhere &= " (Description is not null)"
End If
If chkActiveOnly.Checked Then
If strWhere <> "" Then strWhere &= " AND "
strWhere &= " (Active = 1)"
End If
If strWhere <> "" Then
strSQL &= " WHERE " & strWhere
End If
strSQL &= " " & strOrderBy
cmdSQL.CommandText = strSQL
LoadGrid(cmdSQL)
End Sub
So, note the "pattern". For each control you add, you have a if/then block. You check existing where clause (might be none), and add " AND " to the where clause. You then add parameters to the sql command object.
MANY fail to realize, that you can add parameters to the command object, and you don't even need to have set what the sql source for the sql command object is!!! - they are separate concepts.
So, with above, we are free to check/select or whatever for the filter, and then hit search button.
the above approach works if you have 2 or 25 optional controls.
And VERY important? We NEVER in ANY case ever concatenate user input into that sql string - only ever use parmaters , so this approach is SQL injection safe.
I am new with .net!
I have two gridviews connected to a large database. The first one is returning a list of issues searched by ID while the other is returning the issues searched by subject.
I am trying to get the ID from the gridview returning issues from a select button but when I use selectedRow it doesn't return anything.
I tried multiple methods and this is what I have now. Any Suggestions?
Protected Sub IssuesGV_SelectedIndexChanging(ByVal sender As Object, ByVal e As GridViewSelectEventArgs)
Dim pName As String
pName = IssuesGV.SelectedRow.Cells(0).Text
BindGridComments(pName)
End Sub
Protected Sub IssuesGV_RowDataBound(ByVal sender As Object, ByVal e As GridViewRowEventArgs)
If e.Row.RowType = DataControlRowType.DataRow Then
e.Row.Attributes("onmouseover") = "this.style.backgroundColor='aquamarine';"
e.Row.Attributes("onmouseout") = "this.style.backgroundColor='white';"
e.Row.ToolTip = "Click last column for selecting this row."
' e.Row.Cells(0).Attributes.Add("onclick", )
End If
End Sub
Protected Sub IssuesGV_RowCommand(sender As Object, e As GridViewCommandEventArgs)
' ' Dim row As GridViewRow = IssuesGV.Rows(rowIndex)
' v = row.Cells(1).Text
'v = IssuesGV.SelectedRow.Cells(0).Text
' TextBox1.Text = v
'TextBox1.Text = v
If (e.CommandName = "Select1") Then
Dim index As Int16
index = Convert.ToInt32(e.CommandArgument)
Dim row As GridViewRow
row = IssuesGV.Rows(index)
Dim item As ListItem
item.Text = Server.HtmlDecode(row.Cells(0).Text)
End If
End Sub
My gridview code is the following (the one where I am using the select button):
<asp:GridView ID="IssuesGV" runat="server" AutoPostBack="true" OnRowCommand ="IssuesGV_RowCommand" OnRowDataBound="IssuesGV_RowDataBound" OnSelectedIndexChanged = "IssuesGV_OnSelectedIndexChanged" SelectedIndexChaning ="IssuesGV_SelectedIndexChanging" AutoGenerateColumns="False" DataKeyNames="number" DataSourceID="IssueDS" EnableModelValidation="True">
<Columns>
<asp:BoundField DataField="number" HeaderText="number" ReadOnly="True" SortExpression="number" />
<asp:BoundField DataField="subject" HeaderText="subject" SortExpression="subject" />
<asp:BoundField DataField="description" HeaderText="description" SortExpression="description" />
<asp:BoundField DataField="created_at" HeaderText="created_at" SortExpression="created_at" />
<asp:BoundField DataField="opener_name" HeaderText="opener_name" SortExpression="opener_name" />
<asp:BoundField DataField="project_name" HeaderText="project_name" SortExpression="project_name" />
<asp:ButtonField Text="Select" CommandName="Select1" ItemStyle-Width="30" ButtonType="Button" HeaderText="Select" ShowHeader="True" SortExpression="number" >
<ItemStyle Width="30px" />
</asp:ButtonField>
</Columns>
</asp:GridView>
The error I am receiving is this one:
System.ArgumentOutOfRangeException HResult=0x80131502
Message=Index was out of range. Must be non-negative and less than the
size of the collection. Parameter name: index Source= StackTrace:
Many Thanks!
Front End:
Your GridView should look like this:
<asp:GridView ID="IssuesGV" runat="server" AutoGenerateColumns="false"
OnSelectedIndexChanged="IssuesGV_OnSelectedIndexChanged">
<Columns>
<asp:BoundField DataField="number" HeaderText="number" />
...Some Other Fields
<asp:ButtonField Text="Select" CommandName="Select" ItemStyle-Width="150" />
</Columns>
</asp:GridView>
Back End:
Then add this code OnSelectedIndexChanged of GridView:
Protected Sub IssuesGV_OnSelectedIndexChanged(sender As Object, e As EventArgs)
'Accessing Selected BoundField Column
Dim number As String = IssuesGV.SelectedRow.Cells(0).Text
label.Text = "<b>Number Value:</b> " & number & " <b>"
End Sub
Ref: See full example here.
Edit
For some reason, if OnSelectedIndexChanged method is not firing then you've just need to add below attribute in your GridView header markup:
AutoGenerateSelectButton="True"
This will create a Select link in your GridView rows, which'll fire the OnSelectedIndexChanged method.
PS: If above all workarounds not works then see this post.
When I call gvTags.DataSource = GetTags() and gvTags.DataBind() it shows that all the rows and columns have the appropriate data.
When the OnRowDataBound function is hit, the last columns in my first table row have no data (null values).
The only difference between this table and the others I've created is that I am showing/hiding columns based on a user selection higher in the page. But - the showing/hiding is done within the OnRowDataBound function, where the data is already missing. I have no idea what's going on, or where to even start for looking further.
UPDATE: It looks like the problem is caused by the last three lines of the RowDataBound function. When I remove those three rows, the data displays as it should. So - I need a way to show/hide those three columns based on if a user selects a checkbox elsewhere on the page (Include Removed Entries). If the checkbox is selected, the RemovedBy and RemovedDate columns are visible. If it is not selected, those hide but the Description column is visible.
<asp:GridView ID="gvTags" CssClass="table table-striped" runat="server" AutoGenerateColumns="false"
AllowSorting="false" GridLines="None" OnRowDataBound="gvTags_RowDataBound" DataKeyNames="TagID">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:LinkButton ID="btnRemove" runat="server" OnClick="btnRemove_Click">
Remove
</asp:LinkButton>
<asp:LinkButton ID="btnReapply" runat="server" OnClick="btnReapply_Click">
Re-Apply
</asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="TagID" HeaderText="ID" />
<asp:BoundField DataField="InstalledBy" HeaderText="Installed By" />
<asp:BoundField DataField="InstalledDate" HeaderText="Date Installed" />
<asp:BoundField DataField="RemovedBy" HeaderText="Removed By" />
<asp:BoundField DataField="RemovedDate" HeaderText="Date Removed" />
<asp:BoundField DataField="Description" HeaderText="Description" />
<asp:BoundField DataField="IsRemoved" Visible="false" />
</Columns>
</asp:GridView>
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
If (Page.IsPostBack) Then
Exit Sub
End If
gvTags.DataSource = GetTags()
gvTags.DataBind()
'NOTE - Here, DataSource has complete data (all rows & columns that should have data, do have data)
If (gvTags.Rows.Count > 0) Then
gvTags.HeaderRow.TableSection = TableRowSection.TableHeader
End If
End Sub
Protected Sub gvTags_RowDataBound(ByVal sender As Object, ByVal e As GridViewRowEventArgs)
If (Not e.Row.RowType = DataControlRowType.DataRow) Then
Exit Sub
End If
e.Row.FindControl("btnRemove").Visible = Not Boolean.Parse(DataBinder.Eval(e.Row.DataItem, "IsRemoved").ToString)
e.Row.FindControl("btnReapply").Visible = Boolean.Parse(DataBinder.Eval(e.Row.DataItem, "IsRemoved").ToString)
'NOTE - Here, gvTags.Columns(columnIndex) is null for each of the below three columns (RemovedBy, RemovedDate, and Description)
gvTags.Columns(removedByColumnIndex).Visible = checkbox.Checked
gvTags.Columns(removedDateColumnIndex).Visible = checkbox.Checked
gvTags.Columns(descriptionColumnIndex).Visible = (Not checkbox.Checked)
End Sub
My suggestion: if you columns are to be shown/hidden depending on a CheckBox outside of the grid, you could do this in the markup:
<asp:CheckBox ID="chkBox" runat="server" AutoPostBack="true" ... />
And process the event in code-behind:
Private Sub chkBox_CheckedChanged(sender As Object, e As System.EventArgs) Handles chkBox.CheckedChanged
gvTags.Columns(removedByColumnIndex).Visible = chkBox.Checked
gvTags.Columns(removedDateColumnIndex).Visible = chkBox.Checked
gvTags.Columns(descriptionColumnIndex).Visible = (Not chkBox.Checked)
gvTags.DataSource = GetTags()
gvTags.DataBind()
End Sub
I have web application created with VB Visual Studio 2008. I have a created a new page to display a grid view showing contracts from a database with a certain status. In the grid view i have an item template field with a link button. The default text for the link button is Add.
When the button is clicked, i would like to add the id number of the contract from the db to a list of integers. If the contract id is present on the list, the text of the button should read as 'Remove' and it should then be removed from the list. if it is not present in the list, the text of the button should read as 'add' and it should be added to the list. In the click event for the button, i have the code to achieve this.
The page loads fine and displays the items in the grid view, however when i click the add button it was generating a null exception error pointing to my casting the link button. I then put the grid view in an update panel, and i no longer get the null exception error but now nothing happens.
here is aspx code & vb code for the grid view. the null error was firing on the line with Dim btnT As New LinkButton and the next line with btnT = CType(sender, LinkButton). Any assistance will be greatly appreciated, the strange thing is have very similar code (i practically duplicated the code) in a vb asp.net web site, and it works fine.
<td align="center">
<div class="style82">
Contract Queue
</div>
<hr />
<div class = "queue">
<div class="status">
<asp:Label ID="lblMessage" runat="server"></asp:Label>
</div>
<div>
<asp:UpdatePanel ID="MainUpdate" runat="server">
<ContentTemplate>
<div>
<asp:GridView ID="grdvContract" runat="server" AllowPaging="True"
AllowSorting="True" AutoGenerateColumns="False" BackColor="White"
BorderColor="Black" BorderStyle="Solid" BorderWidth="1px" CellPadding="4"
Font-Names="Arial" Font-Size="Small"
ForeColor="Black" GridLines="Vertical" PageSize="25" Width="100%"
OnRowDataBound="grdvContract_RowDataBound">
<FooterStyle BackColor="#333300" BorderColor="#FF5050" BorderStyle="Solid"
ForeColor="#FF9900" />
<RowStyle BackColor="#F7F7DE" />
<Columns>
<asp:BoundField DataField="dealno" HeaderText="Deal No" SortExpression="dealno" />
<asp:BoundField DataField="Type" HeaderText="Type" SortExpression="Type" />
<asp:BoundField DataField="Currency" HeaderText="Currency"
SortExpression="Currency" />
<asp:BoundField DataField="Amount" HeaderText="Amount"
DataFormatString="{0:#,###,###.00}" SortExpression="Amount" HtmlEncode="false" />
<asp:BoundField DataField="Status" HeaderText="Status"
SortExpression="Status" />
<asp:HyperLinkField DataNavigateUrlFields="dealno" Text='<img src="graphics/txt.gif" border="0" />'
DataNavigateUrlFormatString="deal_ticket_standard.aspx?id={0}"
HeaderStyle-HorizontalAlign="Left"
HeaderText="Standard View" ItemStyle-HorizontalAlign="Left" Target="javascript:window.open ('deal_ticket_standard.aspx?id={0}', 'win', 'height=400,width=400,location=no,menubar=no,resizable,scrollbars,status=no,toolbar=no');">
<HeaderStyle Width="50" />
<ItemStyle HorizontalAlign="Left"/>
</asp:HyperLinkField>
<asp:BoundField DataField="rate" HeaderText="Rate" ReadOnly="True" SortExpression="rate"/>
<asp:BoundField DataField="cDate" HeaderText="Contract Date" ReadOnly="True" SortExpression="cDate" />
<asp:TemplateField HeaderText = "Action" >
<ItemTemplate>
<asp:LinkButton ID="btnAction" runat="server" Text = "Add" AutoPostBack = "False"
OnClick = "btnAction_Click" CausesValidation="False"></asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
</Columns>
<PagerStyle BackColor="#F7F7DE" ForeColor="Black" HorizontalAlign="Right" />
<SelectedRowStyle BackColor="#CE5D5A" Font-Bold="True" ForeColor="White" />
<HeaderStyle BackColor="#6B696B" Font-Bold="True" ForeColor="White" />
<AlternatingRowStyle BackColor="White" />
</asp:GridView>
</div>
<div id="ActionStatus" runat="server" visible="false" class="status">
** <asp:Literal ID="ltActionSuccess" runat="server"></asp:Literal> **
</div>
<div>
<br />
Total Deals to be included in this file: <asp:Label ID="lblTotal" class="total" runat="server"></asp:Label>
<br />
</div>
</ContentTemplate>
</asp:UpdatePanel>
<asp:UpdateProgress ID="MainUpdateProgress" runat="server" AssociatedUpdatePanelID="MainUpdate">
<ProgressTemplate>
<div >
Please wait, loading updated content...
</div>
</ProgressTemplate>
</asp:UpdateProgress>
</div>
</div>
</td>...
Imports System.Data
Partial Public Class contract_queue
Inherits System.Web.UI.Page
Private _DealList As List(Of Integer)
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not Page.IsPostBack Then
DealList = New List(Of Integer)
FillContractQueue()
End If
End Sub
Public Property DealList() As List(Of Integer)
Get
Return _DealList
End Get
Set(ByVal value As List(Of Integer))
_DealList = value
End Set
End Property
Protected Sub grdvContract_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles grdvContract.RowDataBound
Dim grid_row As GridViewRow
grid_row = e.Row
If e.Row.RowType = DataControlRowType.DataRow Then
Dim deal_no As Integer = CInt(DataBinder.Eval(grid_row.DataItem, "dealno"))
Dim btnR As LinkButton = grid_row.FindControl("btnAction")
btnR.Attributes.Add("dealid", deal_no)
'If DealList.Contains(dealno) Then
' btnR.Text = "Remove"
'Else
' btnR.Text = "Add"
'End If
End If
End Sub
Protected Sub btnAction_Click(ByVal sender As Object, ByVal e As System.EventArgs)
Me.ActionStatus.Visible = True
Me.ltActionSuccess.Text = "Test"
Dim total As Integer = 0
total = DealList.Count
Me.lblTotal.Text = total
Dim btnT As New LinkButton
btnT = CType(sender, LinkButton)
Dim deal_id As Integer = btnT.Attributes("dealid")
If DealList.Contains(deal_id) Then
DealList.Remove(deal_id)
btnT.Text = "Add"
total = DealList.Count
Me.ltActionSuccess.Text = "Deal " & deal_id & " added to file"
Me.lblTotal.Text = total
Else
DealList.Add(deal_id)
total = DealList.Count
btnT.Text = "Remove"
Me.ltActionSuccess.Text = "Deal " & deal_id & " removed from file"
Me.lblTotal.Text = total
End If
End Sub
Protected Sub FillContractQueue()
Dim ContractDeals As New DataSet()
'set up db connection'
Dim strConnect As String = ConfigurationManager.ConnectionStrings("ibl_treasuryConnectionString").ConnectionString
Dim objConnection As New System.Data.SqlClient.SqlConnection(strConnect)
Dim strQuery As String
strQuery = "SELECT convert(varchar, t_deal_register.contractdate, 106) AS cDate, t_deal_register.id AS dealno, t_deal_type.dealtype AS Type, t_client.client_name AS Client, t_dealer_ibl.dealer_ibl + '/' + t_dealer_client.dealer_client AS Dealers, t_deal_register.amount AS Amount, t_deal_register.fxrate AS rate, t_status.Status, t_currency.currency + '/' + t_currency_1.currency AS Currency FROM t_deal_register INNER JOIN t_deal_type ON t_deal_register.dealtype = t_deal_type.id INNER JOIN t_client ON t_deal_register.clientname = t_client.id INNER JOIN t_dealer_ibl ON t_deal_register.dealer_ibl = t_dealer_ibl.id INNER JOIN t_dealer_client ON t_deal_register.dealer_client = t_dealer_client.id INNER JOIN t_currency ON t_deal_register.currency = t_currency.id INNER JOIN t_status ON t_deal_register.status = t_status.id INNER JOIN t_currency AS t_currency_1 ON t_deal_register.pay_currency = t_currency_1.id where t_deal_register.status = '14' ORDER BY t_deal_register.id DESC"
Dim objCommand As New System.Data.SqlClient.SqlCommand(strQuery, objConnection)
objConnection.Open()
Try
Dim DealAdapter As New System.Data.SqlClient.SqlDataAdapter(objCommand)
DealAdapter.Fill(ContractDeals)
Catch ex As Exception
Me.lblMessage.Text = ex.Message
Finally
objConnection.Close()
If ContractDeals.Tables.Count > 0 Then
grdvContract.DataSource = ContractDeals
grdvContract.DataBind()
End If
End Try
End Sub
End Class
<asp:TemplateField>
<ItemTemplate>
<asp:LinkButton ID="lnkButtonID" runat="server"
OnClick="lnkButton_Click" Text='<%#DataBinder.GetPropertyValue(Container.DataItem, "ID")%>'
name = '<%#DataBinder.GetPropertyValue(Container.DataItem, "Name")%>'
address = '<%#DataBinder.GetPropertyValue(Container.DataItem, "address")%>'
description = '<%#DataBinder.GetPropertyValue(Container.DataItem, "Description")%>'
></asp:LinkButton>
</ItemTemplate>