Dynamically created Labels and TextBoxes are unable to be positioned - asp.net

I am building a dynamically created popup window that contains a dynamically created grid and controls (Labels and TextBoxes).
The grid part is working correctly, and not an issue. However, the controls are giving me issues.
The idea is to create a Label and a TextBox for each of the columns in the Grid. I am able to create them fine, but am unable to position them at all. label.Location, label.Top, label.point, etc. return an error saying that it is not part of Label. The same thing happens with the TextBox.
When they do display, they appear in a horizontal row with the TextBox overlapping the Label unless the width is set sufficiently large enough (which of course leave a bunch of empty space).
I would like the to be vertically aligned with the TextBox immediately after the Label.
Something like:
labelText: TextBox
These controls are being added into an asp:Panel (pnlFields)
For Each col As DataColumn In dataTable.Columns
Dim label As New Label()
label.Text = col.ColumnName & ": "
label.Height = 24
label.Width = label.Text.Length()
pnlFields.Controls.Add(label)
Dim textBox As New TextBox()
textBox.Height = 24
textBox.Width = 100
pnlFields.Controls.Add(textBox)
Next
I would like to try to have the Label width be as long as the text it contains instead of static, that way I would (hopefully) be able to set the TextBox location to be right after the Label.
In any event, I can't seem to specify a position at all in order to do this.
Any ideas?
Thanks!
Edit: Markup
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
<asp:Panel runat="server" ID="pnlFields" CssClass="FormStyle" Height="600px" />
<asp:Panel runat="server" ID="pnlFinder" CssClass="FormStyle">
<telerik:RadGrid ID="batchRecords" runat="server" Skin="Windows7" ShowHeader="true" AutoGenerateColumns="true" Width="600px" AutoPostBack="true">
<MasterTableView CommandItemDisplay="Bottom" AllowPaging="true">
<CommandItemSettings ShowAddNewRecordButton="false" />
<Columns>
<telerik:GridButtonColumn UniqueName="selectRecord" HeaderText="Edit" CommandName="Select" Text="Edit Record" ButtonType="ImageButton" ImageUrl="~/images/icons/pencil.png">
</telerik:GridButtonColumn>
</Columns>
</MasterTableView>
</telerik:RadGrid>
</asp:Panel>
</asp:Content>

I really, but really don't see the need for creating those text boxes. there is a LARGE number of built in repeating controls. If you create those controls on the fly, then you can NOT wire up the code behind events - so you quite much give up the WHOLE reason for using asp.net and ALL of those great built in controls.
I see no reason why you can inject and include some extra "divs" and apply style to those divs. But, before you go down that road?
You should attempt to make a VERY STRONG case as to why you going down this road as opposed to using a listview, gridview, or a repeater control. They are designed for repeating data over and over - and do so WITH VERY LITTLE code and VERY LITTLE markup.
and where does the data come from that going to fill out these controls? Or even the reverse - where is the reulsts of the controls going to be placed? You see, by using say a repeater or whatever? They are data bound. So, a person can say add 2 or 15 rows of data, and then in ONE sql update operations you can write out ALL of that data! - in other words, you are repeating some controls - but based on what and how is the big question here?
And as noted, if you create + inject such controls, then you can't have nor wire up events for these controls. So, think very long and hard as to the final goal here. You might fix the layout issues, but then your next issue/problem will be event code, and then after that, will be the complex code required to take that input and somehow push it back out to some database. As a result, I really don't recommend this road.
Further more, using one of those built in "repeating" objects allows you with relative ease to enable editing of that data on screen, and as noted, writing back one row, or 15 rows of data can be done with the same code - and with far greater ease then trying to inject dynamic controls into that form. Furthermore, what "id" are you going to use for referencing those controls and once you managed to inject these controls?
The end goal here is the key concept.
I find that gridview is nice - often less mark up. However WHEN you start to have say 3 or more custom controls in that grid? Then I like listview over that of gridview (because listview allows you to drap + drop and use standard asp.net controls WITHOUT having to put that control inside of a template block. But, your case? Only two extra controls for each row of the grid? then sure, stick with grid view.
So, to add those two extra columns to that grid? You can do this:
First, I will use the wizard to create this gridview. I THEN blow out the data sourceID setting and also chop out the datasource control on the form.
So, I count less then 1 minute - drop gridview. Click on the configure data source from the form. This one:
So I configure the data source, generate the gv, AND THEN remove the data source ID and also remove the data source control from the markup. So, it takes 30 seconds of time, and I wind up with this grid:
So, we get this:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="ID">
<Columns>
<asp:BoundField DataField="ID" HeaderText="ID" InsertVisible="False" ReadOnly="True" SortExpression="ID" />
<asp:BoundField DataField="FirstName" HeaderText="FirstName" SortExpression="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="LastName" SortExpression="LastName" />
<asp:BoundField DataField="HotelName" HeaderText="HotelName" SortExpression="HotelName" />
<asp:BoundField DataField="City" HeaderText="City" SortExpression="City" />
</Columns>
</asp:GridView>
And the code to load this grid up is this:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If IsPostBack = False Then
LoadGrid()
End If
End Sub
Sub LoadGrid()
Using cmdSQL As New SqlCommand("SELECT ID, FirstName, LastName, HotelName, City from tblHotels",
New SqlConnection(My.Settings.TEST3))
cmdSQL.Connection.Open()
GridView1.DataSource = cmdSQL.ExecuteReader
GridView1.DataBind()
End Using
End Sub
And now we have this:
Ok, not bad for less time then it took me to WRITE this post!!!
And note how we only up to about what - 3 lines of code to load up the grid?
Super easy.
Ok, so now lets add a label, and a text box to the grid.
Well, just do this for the gv template:
So, note how we just added two extra columns. The markup is like this:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="ID">
<Columns>
<asp:BoundField DataField="ID" HeaderText="ID" InsertVisible="False" ReadOnly="True" SortExpression="ID" />
<asp:BoundField DataField="FirstName" HeaderText="FirstName" SortExpression="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="LastName" SortExpression="LastName" />
<asp:BoundField DataField="HotelName" HeaderText="HotelName" SortExpression="HotelName" />
<asp:BoundField DataField="City" HeaderText="City" SortExpression="City" />
<asp:TemplateField HeaderText = "My label">
<ItemTemplate>
<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText = "My Text Box">
<ItemTemplate>
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Now, when we run the above, we get this:
I mean was that easy or what? And I could have placed that lable + text box in the SAME TEMPLATE column. So you quite much free to add those extra columns to that grid, and we did not have to write code - and in fact it was VERY easy, and the result is we now have that extra two columns - and achieve this WITH GREAT ease.
And we can also with relative ease set/change the values of the label and text box - even based on other colum data from that row, and can do that again with great ease.
So, at the end of the day? I don't suggest you try and manual add two columns when we have such a great approach as outlined above. and even better, is the values the user types into each row and text box can via code be pulled and refreenced from that gv - and done so with great ease for 2 rows, or 20 rows of data.
Edit:
Since the controls and addtions to the gv are to be at run time (dynamic), then you STILL WANT to use the gv object model - fighting against that model is a REALLY bad idea - go with the flow.
So, you can add extra bound field columns to the gv this way:
Sub LoadGrid()
Using cmdSQL As New SqlCommand("SELECT ID, FirstName, LastName, HotelName, City from tblHotels",
New SqlConnection(My.Settings.TEST3))
cmdSQL.Connection.Open()
GridView1.DataSource = cmdSQL.ExecuteReader
AddColumns()
GridView1.DataBind()
End Using
End Sub
Sub AddColumns()
Dim lblfield As New BoundField()
lblfield.HeaderText = "Label1"
GridView1.Columns.Add(lblfield)
Dim txtfield As New BoundField()
txtfield.HeaderText = "TextBox"
GridView1.Columns.Add(txtfield)
End Sub
And then on item bound event, you can also then inject the controls of your choosing like this:
Protected Sub GridView1_RowDataBound(sender As Object, e As GridViewRowEventArgs) Handles GridView1.RowDataBound
If e.Row.RowType = DataControlRowType.DataRow Then
Dim MyLabel As New Label
MyLabel.ID = "Label1"
MyLabel.Text = "Label Text"
e.Row.Cells(5).Controls.Add(MyLabel)
Dim MyTextBox As New TextBox
MyTextBox.ID = "Textbox1"
MyTextBox.Text = "Text box value"
e.Row.Cells(6).Controls.Add(MyTextBox)
End If
End Sub
so, now with this simple markup:
<link href="Content/cuscosky.css" rel="stylesheet" />
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="ID">
<Columns>
<asp:BoundField DataField="ID" HeaderText="ID" InsertVisible="False" ReadOnly="True" SortExpression="ID" />
<asp:BoundField DataField="FirstName" HeaderText="FirstName" SortExpression="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="LastName" SortExpression="LastName" />
<asp:BoundField DataField="HotelName" HeaderText="HotelName" SortExpression="HotelName" />
<asp:BoundField DataField="City" HeaderText="City" SortExpression="City" />
</Columns>
</asp:GridView>
So, with above code? We get the SAME results, and this output:

Edit:
I solved this by creating an HTML Table in the markup, then programmatically adding Rows and Cells with controls (Labels and TextBoxes) and unique IDs. I was then able to find and populate those controls with the correct data.
Worked MUCH easier than trying to manually position each control.
I was able to solve the issue of positioning the controls.
I needed to use label.Style.Add() and put in the values needeed.
It seems to be working correctly now.
Thanks!

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;
}

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

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:

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

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

Row Count for GridView with paging

So I have user controls with GridView tables. I have more tables that are much bigger than this one and have paging enabled, but I'm using this as an example. I want each table to display like this one, where a table with a hundred rows will say "Showing: 1 - 10 of 100" on the first page, "Showing: 11 - 20 of 100" on the second, etc.
This is how it is coded now (in my html file):
<div id="WebsiteHitsMacro">
<umbraco:Macro ID="Macro303" Alias="WebsiteHitsControl" runat="server"></umbraco:Macro>
</div>
<div class="ui-widget-header ui-state-default ui-corner-bl ui-corner-br ui-helper clearfix bottom">
<div class="dataTables_info" id="websitehits_info">Showing: 1-6 of 6</div>
</div>
Here's the ascx code:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataSourceID="SqlDataSource1" CssClass="dataTable" AllowPaging="True"
AllowSorting="True">
<AlternatingRowStyle CssClass="altrow" />
<HeaderStyle CssClass="ui-state-default" />
<Columns>
<asp:BoundField DataField="id" HeaderText="id" SortExpression="id" />
<asp:BoundField DataField="name" HeaderText="name" SortExpression="name" />
</Columns>
</asp:GridView>
I don't know how to get the row count in the first place. Is it possible to have it display in the div I have here?
I hope this makes sense. Thanks.
To get the total amount of rows across all pages of the grid, then use the GridView.Rows, because it represents a collection of all the data rows in your grid. You can use the Count property of that collection, like this:
C#:
int totalRowsCount = GridView1.Rows.Count;
VB.NET:
Dim totalRowsCount As Integer = GridView1.Rows.Count
Now, your problem is that, from what I can see of your posted code, your user control does not expose this information via properties or events that the page can use. I recommend putting this Showing 1-6 of 6 message into the user control itself, so it has component level access to the grid and can easily get the information it needs to display. Either a footer row in the grid or a label that sits right below the actual grid itself.
You said that your Gridview has a paging. By using Dim cnt As Integer = Gridview1.Rows.Count, it only returns the number of rows in Gridview and not the total number of rows the datasource has filtered.
Since you are using SqlDataSource, try this code:
Protected Sub SqlDataSource1_Selected(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.SqlDataSourceStatusEvent Args) Handles
SqlDataSource1.Selected
Dim cnt As Integer = e.AffectedRows
End Sub

Resources