ASP.NET query database with text from textbox without clicking on button - asp.net

I have a datepicker calendar in JS. Once a user clicks on a date, that date gets passed to the asp:TextBox as string. I would like to query my database with the text in textbox without having to click on a button. Is this possible?

Well, there is what, 100's of JS date pickers?
(which one you using might have helped here).
So, it going to depend on how the JS works.
Lets drop in a text box, set autopostback = true, and then add a text change event.
So, we have this markup:
<h2>Choose Date</h2>
<asp:TextBox ID="txtDate" runat="server"
TextMode="Date" AutoPostBack="True" ></asp:TextBox>
and the code behind is this:
Protected Sub txtDate_TextChanged(sender As Object, e As EventArgs) Handles txtDate.TextChanged
Debug.Print("Date changed to " & txtDate.Text)
End Sub
Now run the page and we have this:
Note how that text box already shows a date picker if you set textMode = date. Maybe you don't need a JS date picker then?
Ok, so lets select a date:
And because I have autopost-back = true, I see this in output:
Output:
So, in your server side text changed event - it should trigger. But that triggering of the text changed event may well depend on how and what kind of out of the 1000+ date picker JS examples I can find on the web that you are using here.
So now lets query the database based on that value then right?
So, say we have this markup:
<h2>Choose Date</h2>
<asp:TextBox ID="txtDate" runat="server" TextMode="Date" AutoPostBack="True" ></asp:TextBox>
<asp:GridView ID="GridView1" runat="server" 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="VisitDate" HeaderText="Vist" DataFormatString="{0:yyyy-MM-dd}" />
<asp:BoundField DataField="Description" HeaderText="Description" />
</Columns>
</asp:GridView>
We select a date, and show visits for that date.
Our code thus becomes this:
Protected Sub txtDate_TextChanged(sender As Object, e As EventArgs) Handles txtDate.TextChanged
Debug.Print("Date changed to " & txtDate.Text)
Using conn As New SqlConnection(My.Settings.TEST4)
Dim strSQL =
"SELECT * from tblHotels WHERE VisitDate = #VisitDate ORDER BY HotelName"
Using cmdSQL = New SqlCommand(strSQL, conn)
cmdSQL.Parameters.Add("#VisitDate", SqlDbType.DateTime).Value = txtDate.Text
conn.Open()
GridView1.DataSource = cmdSQL.ExecuteReader
GridView1.DataBind()
End Using
End Using
End Sub
And we now have this:

Related

How do I make a read only cell editable in a gridview control in asp using vb?

Hi me again with another question.
I'm using VS2019 and VB on an aspx page. I have a gridview that has Edit enabled.
enter image description here
When a user clicks the EDIT link Progress % and Comments become editable.
What I want to do is make the Goal be editable if Approved is set to No.
How can I do this?
<asp:GridView ID="grdgoals" runat="server" AutoGenerateColumns="False" DataSourceID="DS1" Height="225px" Width="1001px" BorderColor="#003960" BorderStyle="Solid" BorderWidth="1px" DataKeyNames="goalid" EmptyDataText="No goals found." Font-Bold="True" Font-Names="Calibri" Font-Overline="False" Font-Size="Medium" Font-Strikeout="False" ForeColor="#00AD86" ShowHeaderWhenEmpty="True" AllowSorting="True" style="margin-right: 21px">
<Columns>
<asp:BoundField DataField="goalid" HeaderText="goalid" ReadOnly="True" SortExpression="goalid" Visible="False" />
<asp:CommandField EditText="EDIT" ShowEditButton="True" ShowHeader="True">
<HeaderStyle BorderColor="#003960" />
<ItemStyle Font-Names="Calibri" Font-Underline="True" ForeColor="#006EAA" HorizontalAlign="Center" BorderColor="#003960" Width="20px" />
</asp:CommandField>
<asp:BoundField DataField="goaltext" HeaderText="Goal" SortExpression="goaltext" ReadOnly="True" >
<HeaderStyle BorderColor="#003960" />
<ItemStyle BorderColor="#003960" Width="250px" />
</asp:BoundField>
<asp:BoundField ConvertEmptyStringToNull="True" DataField="type" HeaderText="Type" ReadOnly="True" >
<ItemStyle Width="70px" />
</asp:BoundField>
<asp:BoundField DataField="progress" HeaderText="Progress %" SortExpression="progress" >
<HeaderStyle BorderColor="#003960" />
<ItemStyle HorizontalAlign="Center" BorderColor="#003960" VerticalAlign="Middle" Width="20px" />
</asp:BoundField>
<asp:BoundField DataField="comments" HeaderText="Comments" SortExpression="comments" ItemStyle-Wrap="true">
<ControlStyle Height="400px" Width="240px" />
<HeaderStyle BorderColor="#003960" />
<ItemStyle BorderColor="#003960" Width="250px" HorizontalAlign="Left" VerticalAlign="Middle" />
</asp:BoundField>
<asp:BoundField DataField="approved" HeaderText="Approved" ReadOnly="True" SortExpression="approved" >
<ItemStyle HorizontalAlign="Center" Width="40px" />
</asp:BoundField>
</Columns>
<EditRowStyle HorizontalAlign="Left" VerticalAlign="Top" />
<HeaderStyle ForeColor="#006EAA" />
</asp:GridView>
I have searched online looking for answer but haven't found anything.
Ok, so how much extra code is it to simple drop in a "plain jane" button to click on and edit?
It not much!!!
You do have to bear the cost/time of building a form layout for the one row, but at the end of the day:
this tends to be "easy" for the users.
You can also then move the row delete button to that "form layout" area for editing one record. (this means you don't need a delete record button on the GV - not a huge deal, but that means users have to make a "bit more" effort to delete a row of data if that option is desired).
However, the "why" of having a detail edit layout?
You can now have MUCH more control over your logic (such as the rule to allow what to edit, change or even "enable" based on other values. And such code is clean easy server side code.
And this allows far more code logic into the editing of that data. (required fields, formatting, all that stuff.
Best bonus feature?
Such a approach now ALSO allows adding of new records in a MUCH more user friendly way, since now the "edit" area you build ALSO can be used as the "add new" record area. (so, you save having to write separate code for edit and adding - the one solution does both). And this also means the end user has the "same" experience when editing existing, or adding new - it shortens the user learning curve.
Now, about the only downside?
Well, when starting out, those wizards can be a real gift horse. And I still after all these years often use the wizard(s) to create the GV.
however, I THEN clean it up a bit, and remove things from the page.
(such as removing the datasource on the page).
And the other tip?
If possbile, build a few "helper" routines. They can be used over and over.
For example, I became VERY tired of having to type in code with a row of data, and then "please fill out" those controls on the page with that data.
Then after done, we have to take that those controls, and send back to the database. We do this "over and over". And the code to do this is darn near the "same" over and over. So, then, why not write one sub routine that can do this for ANY page we work on!!!
So, here is a working approach.
for the GV, then the markup becomes rather clean - just some fields.
Say, like this markup:
<asp:GridView ID="GridView1" runat="server" Width="40%"
AutoGenerateColumns="False" DataKeyNames="ID"
CssClass="table table-hover table-striped" >
<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 myshadow"
OnClick="cmdEdit_Click"
/>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Note a few things in above:
If we don't use width, or use 100%? The GV will expand to the WHOLE page - it is what we call "responsive".
I assume that you have bootstrap installed, and most projects do (by default).
The result is a "very" nice grid, and the fonts + spacing and layout is "tweaked" by bootstrap. The result is quite nice.
Code 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
Note the "helper" routine MyrstP. I use this "over and over" everywhere.
(I'll post that at end of this post).
So, I removed the Sqldatasourc1 from the page. I find that you obtain/enjoy MUCH more control over the code. (but, if you don't have a helper routine, then setting up a query + connection and all that jazz? Then you might as well just stick with the wizard generated SqlDataSource on the page. But, you find over time that using code behind is a "less effort" choice, and one that gives you far more control (say to filter, or do other things).
And note the table hover (you get a "nice" row hover effect), and note the table-striped. That gives you a nice alternating row shade - and you do not need a messy "alternating" template.
So far? We have a VERY clean markup, and so far VERY little code has been written.
Now, not the button we dropped into the GV. That is a plan jane asp.net button. We don't need to use "speical" commands, "speical" code or anything. Just a good old fashioned button and button click.
However, do note that we have a click event for the button. Normally, I often just double click on a button, and then a code behind stub is created, and we are jumped to the code behind editor.
however, since the button is "nested" in a GV, then we can't double click on that button to create a event.
So, flip to markup. And in markup type in
OnClick=
WHEN you hit the "=", then intel-sense should pop up and gives you the option to create the event. (since we can't use double click on button to do this).
So, it looks like this:
And thus the code is for 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)
ViewState("PKID") = intPK
fLoader(EditRecord, rstHotel.Rows(0))
GridView1.Visible = False ' Hide GV
EditRecord.Visible = True ' show edit area
End Sub
Again, note the small amount of code.
The button click thus:
we get GV row
we get GV row PK database ID (using datakeys feature)
we pull that data row into data table
we call the floader() routine that takes ONE row, fills out controls.
the resulting effect is thus this:
And our helper MyRstP routine is this:
Public Function MyrstP(cmdSQL As SqlCommand,
Optional cmdOnly As Boolean = False) As DataTable
Dim rstData As New DataTable
Using mycon As New SqlConnection(GetConstr)
Using (cmdSQL)
cmdSQL.Connection = mycon
mycon.Open()
If cmdOnly Then
cmdSQL.ExecuteNonQuery()
Else
rstData.Load(cmdSQL.ExecuteReader)
End If
End Using
End Using
Return rstData
End Function
I'll post more code from above (later this evening)., and say have some "conditional" code. Say if the hotel not active, we can't edit description.

styling certain rows in my gridview asp.net

so I have a gridview which is displaying a db table I have.
I dont create the table manually obviously as this is what <%#Eval("text")%>' and Bind() do.
I created a unique table with my sql query to add two rows of sum in the bottom of the table, ( 2 last records), my question is:
is there a way in which I can access those rows to style them?
I think its not possible but still Im asking maybe Ill find out that theres a way.
thanks
Yes, the need to style a individual cell (auto generated columns, or bound columns), or even style the whole row.
Let's do all 3
First up, style a "cell" (these are in the cells collection, and autogenerated columns, and NON templated columns).
So, say this simple grid
<asp:GridView ID="GridView1" runat="server" Width="40%"
AutoGenerateColumns="False" DataKeyNames="ID" CssClass="table table-hover">
<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:TemplateField HeaderText="Description">
<ItemTemplate>
<asp:Label ID="lblDescript" runat="server"
Text='<%# Eval("Description") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Active" ItemStyle-HorizontalAlign="Center">
<ItemTemplate>
<asp:CheckBox ID="chkActive" runat="server"
Checked='<%# Eval("Active") %>' />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
(note how I included BOTH templated columns which have plain jane asp.net controls like label, textbox etc., or the built in GV columns (data bound ones, or auto generated)
Code 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"
Using conn As New SqlConnection(My.Settings.TEST4)
Using cmdSQL As New SqlCommand(strSQL, conn)
conn.Open()
Dim rst As New DataTable
rst.Load(cmdSQL.ExecuteReader)
GridView1.DataSource = rst
GridView1.DataBind()
End Using
End Using
End Sub
And we now have this:
Ok, so let's do example 1 - lets color the "city" Colum in above. Note how "city" is a "bound field".
So, auto generated, or bound fields = cells collection.
So, for things like conditional formatting, even combine some columns, change color, hide show images, or whatever?
you use the GV row databound event. (and this applies well to listview, repeaters, etc.)
So, lets say for city = Edmonton, we want a light blue cell, and for city = "Edmonton", we want some light green.
So, we use the row bound event.
This code:
Protected Sub GridView1_RowDataBound(sender As Object, e As GridViewRowEventArgs)
If e.Row.RowType = DataControlRowType.DataRow Then
Select Case e.Row.Cells(3).Text
Case "Edmonton"
e.Row.Cells(3).BackColor = System.Drawing.Color.SkyBlue
Case "Banff"
e.Row.Cells(3).BackColor = System.Drawing.Color.LightGreen
End Select
End If
End Sub
And we now have this:
However, the above for "templated" colums works a bit different.
Lets say we want to highligh the description when check box = true (checked).
In that case, we can't (don't) use the cells colleciton, but for templated controls, we use find control.
Like this:
Dim cActive As CheckBox = e.Row.FindControl("chkActive")
If cActive.Checked Then
Dim lblDes As Label = e.Row.FindControl("lblDescript")
lblDes.Font.Italic = True
e.Row.Cells(4).BackColor = System.Drawing.Color.LightGray
End If
NOTE how we EVEN set the font to italic in the label control.
And now we see this:
NOTE VERY close how we use findcontrol to get those templated controls.
Last but not least - bonus:
let's highlight the whole row for active, and NOT EVEN have the check box column in the GV (but it is in the database source).
So, say this markup for the columns:
<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:TemplateField HeaderText="Description">
<ItemTemplate>
<asp:Label ID="lblDescript" runat="server"
Text='<%# Eval("Description") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
</Columns>
So, "active" check box is NOT EVEN displayed in the GV, (but, it is in the data source that feeds the gv).
So, we can do this:
Protected Sub GridView1_RowDataBound(sender As Object, e As GridViewRowEventArgs)
If e.Row.RowType = DataControlRowType.DataRow Then
Dim gData As DataRowView = e.Row.DataItem ' Grid data - NOT the GV row!!!!!!
If gData.Item("Active") = True Then
e.Row.Style.Add("Background-color", "LightGray") ' highlight whole row.
End If
End If
End Sub
And we now get this:
Just keep in mind that the "dataitem" (the full database row) is ONLY avaiable during the row data bind, and it WILL/DOES go out of scope once data binding is complete.
so basically using pretty much similar logics as albert's reply, I ended up catching two last rows manually and changing their colors.
protected void grdReports_PreRender(object sender, EventArgs e)
{
//finding 2 last rows, changing backcolor to the sum specified color '#5D7B9D' and the forecolor to white
//first table ( annual )
GridViewRow lastRow = grdReports.Rows[grdReports.Rows.Count - 1];
lastRow.BackColor = System.Drawing.Color.FromName("#5D7B9D");
lastRow.ForeColor = Color.White;
GridViewRow secondToLastRow = grdReports.Rows[grdReports.Rows.Count - 2];
secondToLastRow.BackColor = System.Drawing.Color.FromName("#5D7B9D");
secondToLastRow.ForeColor = Color.White;
//second table ( requested )
GridViewRow lastRowSecond = grdReports2.Rows[grdReports2.Rows.Count - 1];
lastRowSecond.BackColor = System.Drawing.Color.FromName("#5D7B9D");
lastRowSecond.ForeColor = Color.White;
GridViewRow secondToLastRowSecond = grdReports2.Rows[grdReports2.Rows.Count - 2];
secondToLastRowSecond.BackColor = System.Drawing.Color.FromName("#5D7B9D");
secondToLastRowSecond.ForeColor = Color.White;
}

How do I enable row selection in an ASP GridView without disabling EnableEventValidation?

I have an ASPX page that includes a GridView. I want to be able to select a row from the grid, and populate another section of the page based on the selected row. It works if I have EnableEventValidation="false" in the <%# Page %> line, but I have been told that I cannot use that because of a security concern. When I don't include it, selecting a grid row throws an "Invalid postback or callback argument" exception.
How can I implement row selection without disabling event validation?
Here is my code:
ASPX page:
<asp:GridView runat="server" ID="TheGrid" AutoGenerateColumns="false" DataKeyNames="id" EmptyDataText="No Data Found" AllowSorting="true">
<Columns>
<asp:BoundField DataField="FirstName" HeaderText="First Name" ReadOnly="true" SortExpression="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="Last Name" ReadOnly="true" SortExpression="LastName" />
<asp:BoundField DataField="Email" HeaderText="Email" ReadOnly="true" SortExpression="Email" />
</Columns>
</asp:GridView>
ASPX.VB code:
Protected Sub TheGrid_RowDataBound(sender As Object, e As GridViewRowEventArgs) Handles TheGrid.RowDataBound
If e.Row.RowType = DataControlRowType.DataRow Then
e.Row.Attributes("onclick") = Page.ClientScript.GetPostBackClientHyperlink(TheGrid, "Select$" & e.Row.RowIndex)
e.Row.Attributes("style") = "cursor:pointer"
End If
End Sub
Protected Overrides Sub Render(writer As HtmlTextWriter)
ClientScript.RegisterForEventValidation("TheGrid")
MyBase.Render(writer)
End Sub
Note that when I select a row, the exception is thrown somewhere between Page_Load and Render.
Ok, lets wire up the GV two ways.
First way, drop in a plane jane button for the row click
(we will delete the button and add row click in 2nd example).
so, say this simple GV
<div id="MyGridArea" runat="server" clientidmode="static">
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataKeyNames="ID"
CssClass="table table-hover" Width="60em" GridLines="None"
ShowHeaderWhenEmpty="true">
<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" />
<asp:BoundField DataField="Description" HeaderText="Description" />
<asp:TemplateField>
<ItemTemplate>
<asp:Button ID="cmdEdit" runat="server" Text="Edit" CssClass="btn myshadow"
OnClick="cmdEdit_Click" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</div>
Note how we just dropped in a plane jane button.
And our code to fill out above is this:
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()
Dim strSQL = "SELECT * FROM tblHotelsA ORDER BY HotelName"
GridView1.DataSource = Myrst(strSQL)
GridView1.DataBind()
End Sub
And now we have this:
Ok, so next part is to drop in a "div" area that allows edit of one row.
So, again, quite much plan jane controls.
And we can "hide" grid when we edit, and show edit area div.
But, I often use jQuery.UI. Really amounts to much the same code as simple hide/show, but this way jQuery.UI turns that SAME div into a nice pop up area.
So, that div area might look like this:
<div id="EditRecord" runat="server" style="float: left; display: none" clientidmode="Static">
<br />
<div style="float: left" class="iForm">
<label>HotelName</label>
<asp:TextBox ID="txtHotel" runat="server" f="HotelName" Width="280">
</asp:TextBox>
<br />
<label>First Name</label>
<asp:TextBox ID="tFN" runat="server" f="FirstName" Width="140"></asp:TextBox>
<br />
<label>Last Name</label>
<asp:TextBox ID="tLN" runat="server" f="LastName" Width="140"></asp:TextBox>
<br />
<label>City</label>
<asp:TextBox ID="tCity" runat="server" f="City" Width="140"></asp:TextBox>
<br />
<label>Province</label><asp:TextBox ID="tProvince" runat="server" f="Province" Width="75"></asp:TextBox>
</div>
etc. etc. etc.
so, now lets wire up the button above.
The button will simple:
Get current grid row
Get PK id
Load up div and display.
So, that code is this:
Protected Sub cmdEdit_Click(sender As Object, e As EventArgs)
Dim btn As Button = sender
Dim gRow As GridViewRow = btn.NamingContainer
EditRow(gRow.RowIndex)
End Sub
Sub EditRow(rowNum As Integer)
Dim intPK As Integer = GridView1.DataKeys(rowNum).Item("ID")
Dim strSQL As String = "SELECT * FROM tblHotelsA WHERE ID = " & intPK
Dim rstData As DataTable = Myrst(strSQL)
' load up our edit div
fLoader(Me.EditRecord, rstData.Rows(0))
ViewState("PK") = intPK
ScriptManager.RegisterStartupScript(Me.Page, Page.GetType, "mypopedit", "popedit()", True)
End Sub
As noted, I added a popup from jQuery.UI, but we could just use plain jane "div" and hide/show the grid and show the edit area (or like you have, have that edit area in full view).
(fLoader is a routine I built some time ago - I like everyone became VERY tired of typing code over and over to fill out text boxes etc., so for any text box etc., I use a "made up" attribute called f="Data base column name", and that routine just loops the controls on the form and fills them out. No different than hand coding simple assignments to controls, but with this code I can re-use it over and over.
So, we now see, get this:
Ok, so the only next goal is to add a row click
(and not use that edit button).
So, then all we need is a routine that will get the current row index, and call our edit row routine we have above.
So, we use row data bound, and add that click event that way.
but, do note how the above button click gets the current row. That nice short code works for repeaters, listview etc. (we used naming container).
But, if you want a row click in place of that button?
Then on row data bound, add this code:
Protected Sub GridView1_RowDataBound(sender As Object, e As GridViewRowEventArgs) Handles GridView1.RowDataBound
If e.Row.RowType = DataControlRowType.DataRow Then
e.Row.Attributes.Add("onclick",
"__doPostBack('myrowedit'," & e.Row.RowIndex & ")")
End If
End Sub
And in our page load event, we have this:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
LoadGrid()
Else
If Request("__EVENTTARGET") = "myrowedit" Then
EditRow(Request("__EVENTARGUMENT"))
End If
End If
End Sub
And a handy dandy routine that returns a table based on SQL I used above was this:
Public Function Myrst(strSQL As String) As DataTable
Dim rstData As New DataTable
Using mycon As New SqlConnection(My.Settings.TEST4)
Using cmdSQL As New SqlCommand(strSQL, mycon)
mycon.Open()
rstData.Load(cmdSQL.ExecuteReader)
End Using
End Using
Return rstData
End Function
So, all in all, not a lot of code.
You can try the above working example here:
http://www.kallal.ca/Website11/WebForm2

Gridview Edit Mode - Drop down list does not show blank value

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.

How to filter a data grid view in accordance with one or multiple drop down list selections

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.

Resources