Insert Rows In Gridview - asp.net

I have a standard Gridview which is populated from a SQLDataSource. The Gridview will always have 17 rows. Can anyone please give me an example of how to manually insert rows into it at designated row spots? For example, insert a new row into rows 3 and 5.
Thanks

Well, it not at all clear why say inserting at row 5, or at row 8 is important here?
Remember, when we used desktop PC - single user, or say used punch cards?
Then order of data entered DID matter. But, we now don't use punched cards, and thus order of such data does not really matter from a database point of view. I mean, if you have multiple users entering data, and I insert at row 5, then what happens if 3 other uses also did the same. Now that record is in the 8th position. So, introduction of a "order" or some "position" NEEDS some further context here - in other words what is the goal here?
when working with a database, the FIRST rule is that data does NOT have order. And if YOU need some kind of order, say like date of entry, or even say order of new records added, then you the developer needs to design that into your software.
Now, having stated the above? Sure, there are class problems or say UI interface types of issues in which you might have say a order of 5 boxes, and you need to offer the user the ability to re-order those 5 items in ANY order you wish.
Ok, so having stated above?
Well, it not clear how the records were entered in the first place. and it not clear HOW the record that exists in the 5th position is supposed to be the 5th record.
Ok, now regardless of the above?
The trick to adding rows, or deleting rows, or inserting data? Do this at the data level, and NOT at the gridview level. This not only separates out the UI layer, and the data layer? It also saves world poverty and boatloads of complex code.
So, lets assume we have a column called "myorder". And if you don't have this column in the table, then you really quite much need to add it, since as I stated, some data order does not exist by magic, but in fact has to be "designed" and "managed" by YOU THE developer!!!
So, lets take a simple gv like this:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataKeyNames="ID" CssClass="table borderhide" >
<Columns>
<asp:TemplateField HeaderText="First" ><ItemTemplate>
<asp:TextBox ID="txtFirst" runat="server" Text='<%# Eval("FirstName") %>' Width="80px">
</asp:TextBox>
</ItemTemplate></asp:TemplateField>
<asp:TemplateField HeaderText="Last"><ItemTemplate>
<asp:TextBox ID="txtLast" runat="server" Text='<%# Eval("LastName") %>' Width="80px">
</asp:TextBox>
</ItemTemplate></asp:TemplateField>
<asp:TemplateField HeaderText="Hotel"><ItemTemplate>
<asp:TextBox ID="txtHotel" runat="server" Text='<%# Eval("HotelName") %>'></asp:TextBox>
</ItemTemplate></asp:TemplateField>
<asp:TemplateField HeaderText="Description" ><ItemTemplate>
<asp:TextBox ID="txtDescription" runat="server" Text='<%# Eval("Description") %>'
TextMode="MultiLine" Rows="3" Columns="45"
></asp:TextBox>
</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>
Ok, and our code to load the grid. and as noted, we will persit the data source for the grid, since we need to do those inserts.
So, our code to load:
Dim rstData As New DataTable
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
LoadData()
LoadGrid()
Else
rstData = ViewState("rstData")
End If
End Sub
Sub LoadData()
Using conn As New SqlConnection(My.Settings.TEST4)
Dim strSQL = "SELECT * FROM tblHotelsA ORDER BY MyOrder"
Using cmdSQL As New SqlCommand(strSQL, conn)
conn.Open()
rstData.Load(cmdSQL.ExecuteReader)
End Using
End Using
End Sub
Sub LoadGrid()
rstData.DefaultView.Sort = "MyOrder"
GridView1.DataSource = rstData
GridView1.DataBind()
RowCount.Value = rstData.Rows.Count
ViewState("rstData") = rstData
End Sub
and we now have this:
So, now we have that add button. That button will add the row to the grid, and prompt us for the location (what row to insert at).
so, the button looks like this:
<asp:Button ID="cmdSave" runat="server" Text="Save Changes" style="float:left" CssClass="btn"/>
<asp:Button ID="cmdAddRow" runat="server" Text="+Add New" style="float:right" CssClass="btn"
OnClientClick="return askwhatrow(this);"
/>
<asp:HiddenField ID="WhatRow" runat="server" ClientIDMode="Static"/>
<asp:HiddenField ID="RowCount" runat="server" ClientIDMode="Static"/>
<script>
function askwhatrow(btn) {
MyRowCount = $('#RowCount').val()
strMsg = "There are row 1 to " + MyRowCount + "\n" +
"What row to insert new record?"
strAns = prompt(strMsg)
if (strAns === null) {
return false
}
if ((strAns < 1) || (strAns > MyRowCount) ) {
alert("only 1 to " + MyRowCount + " is allowed")
return false
}
// ok, set the row insert location, and run our server side buttion
$('#WhatRow').val(strAns)
return true
}
</script>
So, when we click on add row, we get this prompt:
I of course entered say 2 (or your 5 for your example).
the js code will prompt the user, but of couse if the user hits cancel, then the button code (code behind server) will not run. The code to add the row of data now looks like this:
Protected Sub cmdAddRow_Click(sender As Object, e As EventArgs) Handles cmdAddRow.Click
' add new row to grid at location choosen by user:
GridToTable() ' save any possbile edits by user
Dim InsertLocation As Integer = WhatRow.Value
For Each OneRow In rstData.Rows
If Int(OneRow("MyOrder")) >= InsertLocation Then
OneRow("MyOrder") += 1
End If
Next
' setup new row - some defaults
Dim NewRow As DataRow = rstData.NewRow
NewRow("MyOrder") = InsertLocation
NewRow("Active") = False
rstData.Rows.Add(NewRow)
LoadGrid()
End Sub
Again, note how VERY easy it is to add that row of data. That's because we add the row into the table, and then simple re-bind the grid to display that new record. In other words, don't try to manipulate the gv, but ONLY manipulate the data!!! (that way we save world poverty and you starving from having to write too much code).
So, after we do the above, we see this:
So, with above grid? You can tab around (almost like excel). You can edit any row, make any changes you want.
We then have that ONE save button. All that does is send gv data back to the table, AND THEN IN ONE operation sends the data back to the database.
The code looks like:
Protected Sub cmdSave_Click(sender As Object, e As EventArgs) Handles cmdSave.Click
GridToTable()
Using conn As New SqlConnection(My.Settings.TEST4)
Dim strSQL = "SELECT * FROM tblHotelsA"
Using cmdSQL As New SqlCommand(strSQL, conn)
conn.Open()
Dim da As New SqlDataAdapter(cmdSQL)
Dim daU As New SqlCommandBuilder(da)
da.Update(rstData)
End Using
End Using
End Sub
Sub GridToTable()
' send all data from gv to local table
For Each gvRow As GridViewRow In GridView1.Rows
Dim pkID As Integer = GridView1.DataKeys(gvRow.RowIndex).Item("ID")
Dim OneRow As DataRow = rstData.Select("ID = " & pkID).FirstOrDefault
OneRow("FirstName") = CType(gvRow.FindControl("txtFirst"), TextBox).Text
OneRow("LastName") = CType(gvRow.FindControl("txtLast"), TextBox).Text
OneRow("HotelName") = CType(gvRow.FindControl("txtHotel"), TextBox).Text
OneRow("Description") = CType(gvRow.FindControl("txtDescription"), TextBox).Text
OneRow("Active") = CType(gvRow.FindControl("chkActive"), CheckBox).Checked
Next
End Sub
So in above, we send all edits, all additions (and if you have or add a delete button to each row, then even deletions are ALL SEND back to the database with the above simple few lines of code. As noted, this was and is possible since we persisted the rstData that drives the GV.
and really nice? Well, for 30+ years, every user on the planet who used Excel, or used any accounting system, or any other computer software? They can bounce around in that grid, make changes. And then with one simple save button send the whole she-bang back to the database.

Related

asp.net get table cell text

I'm developping an asp.net Web application.
I have a table and I add rows/cells to the table through code :
<asp:Table ID="Table2" runat="server" Style="table-layout:auto;" GridLines="Both">
<asp:TableRow runat="server" Enabled="False" Font-Bold="True" HorizontalAlign="Center" VerticalAlign="Top" BackColor="#FF704C" ForeColor="Black">
<asp:TableCell runat="server">Famille</asp:TableCell>
<asp:TableCell runat="server">Editeur</asp:TableCell>
<asp:TableCell runat="server">Référence</asp:TableCell>
<asp:TableCell runat="server">Solutions</asp:TableCell>
<asp:TableCell runat="server">Nature</asp:TableCell>
<asp:TableCell runat="server">Unité</asp:TableCell>
<asp:TableCell runat="server">Usage</asp:TableCell>
<asp:TableCell runat="server">Version</asp:TableCell>
<asp:TableCell runat="server">PP net (€)</asp:TableCell>
<asp:TableCell runat="server">Quantité</asp:TableCell>
</asp:TableRow>
</asp:Table>
--
Dim tfp As New TextFieldParser(My.Settings.FilePath)
tfp.Delimiters = New String() {My.Settings.Delimiter}
tfp.TextFieldType = FieldType.Delimited
tfp.ReadLine() ' skip header
Dim Ligne As Integer = 0
While tfp.EndOfData = False
Dim fields = tfp.ReadFields()
Dim trow As New TableRow
Ligne = Ligne + 1
For i = 0 To 8
Dim tcell As New TableCell
tcell.Controls.Add(New LiteralControl(fields(i)))
trow.Cells.Add(tcell)
Next
Table2.Rows.Add(trow)
End While
Later in code, after the user click on a button, I want to get the text which is in the cell, but I always get an empty string.
MyCell = table2.rows(3).Cells(2)
? Mycell.text
""
How can I get the text which is inside the cell ?
Thank you
Ok, the main issue, is that the asp.net "table" has ONE huge big nasty issue.
Asp.net tables do NOT have viewstate nor persistence. So, in code when you add some rows, they are objects added - but NOT with viewstate.
So, your code would have to RE-RUN every time!!!!
In other words, if you run some code to add a row, you have to save that "list" or object of additions, and then on each page load - re-create, and re-add that data each time.
As a result, you are MUCH ,but I mean REALLY BEYOND WORLD poverty better off to use a control with persistence (viewstate) build in.
EVEN in that case where you want to persist the data, I STRONG suggest you persist ONLY the data table used (note how I said the data table - NOT the markup, nor the HTML markup table).
And we do not yet need to have a database to do this!!!
Of course I grasp this is just for learning, but at the end of the day? That data needs to be placed in a database. You then do the data adding, deleting, manipulation, processing against the database. If you need to show updated data as a result (say adding a new row to the database), YOU THEN RE-BIND the control on the form.
so, keep the concept of working with the data 100% separate from the control or so called UI (the web page).
Again, I 100% grasp the goal of learning, and starting out simple. The problem, is that eventually, that data WILL and NEEDS to be in a table. This will allow data base operations, or at the VERY least allow you to use code to add rows, reference a column etc.
so, I suggest you use a GridView, and THEN also create a data table (in code behind).
So, our markup now becomes this:
<asp:GridView ID="GridView1" runat="server" CssClass="table" Width="50%"
ShowHeaderWhenEmpty="true" HeaderStyle-BackColor="LightGray">
</asp:GridView>
<br />
<asp:Button ID="Button1" runat="server" Text="Add new row" CssClass="btn" />
And now our code to create the table, and also code for the add button.
We have this now:
Dim rstData As New DataTable
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
' first page load - create a table,
' send to our grid
CreateTable
LoadGrid
Session("rstData") = rstData
Else
rstData = Session("rstData")
End If
End Sub
Sub CreateTable()
rstData.Columns.Add("Famille")
rstData.Columns.Add("Editeur")
rstData.Columns.Add("Référence")
rstData.Columns.Add("Solutions")
rstData.Columns.Add("Nature")
rstData.Columns.Add("Unité", GetType(Integer))
rstData.Columns.Add("Usage")
rstData.Columns.Add("Version", GetType(Double))
rstData.Columns.Add("PP Net(€)", GetType(Double))
rstData.Columns.Add("Quantité", GetType(Double))
End Sub
Sub LoadGrid()
GridView1.DataSource = rstData
GridView1.DataBind()
End Sub
Protected Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
' add a new row to our table
Dim MyNewRow As DataRow = rstData.NewRow
MyNewRow("Famille") = "this is test" ' example refernce by colum name
MyNewRow(1) = "My Editeur" ' example refernce by colum index
rstData.Rows.Add(MyNewRow) ' send new row to the table
LoadGrid() ' re-display grid to show this new row
End Sub
And when I run above, click the button, I now see this:
Note how we had much less markup, but of course a bit of extra code. However, if that table comes from a database, then we did not even have the code to "create" the table, since in most cases, that table and data would be in a database.
Other advantages?
Well, I can now format the grid, increase column lengths, even drop in a image control, or whatever I like.
In above, I did let the grid load the data table, and format the column widths, but you will often of course want to control the column widths, settings, and even what kind of control to use here.
In fact, if you have a boatload of custom controls on the grid you want, then often I suggest using a ListView in place of GridView (the hard part and learning curve is to learn when and what control to use - you have so many to choose from!!!).
So, I suggest the above.
You can then say I want the 2nd row, and cell like this:
rstData.Rows(1).Item("Famile")
rstData.Rows(1).Item(0)
Again, you can reference column(s) by number (index) or by name.
And say I want even MORE control, then say I have a grid like this:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataKeyNames="ID" CssClass="table" >
<Columns>
<asp:BoundField DataField="Fighter" HeaderText="Fighter" />
<asp:BoundField DataField="Engine" HeaderText="Engine" />
<asp:BoundField DataField="Thrust" HeaderText="Thrust" />
<asp:BoundField DataField="Description" HeaderText="Description" />
<asp:TemplateField HeaderText="Preview">
<ItemTemplate>
<asp:Image ID="Image2" runat="server" ImageUrl = '<%# Eval("ImagePath") %>' Width="140" />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="View">
<ItemTemplate>
<asp:Button ID="cmdView" runat="server" Text="View" CssClass="btn"
CommandArgument = '<%# Eval("ImagePath") %>' OnClick="cmdView_Click" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Note how we now have AutoGenerateColumns = false. That's because I want to "control" each column such as width, etc. And I wanted a image control in that "table".
So, my code to load up the above is now this:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
LoadGridF()
End If
End Sub
Sub LoadGridF()
Using conn As New SqlConnection(My.Settings.TEST4)
Using cmdSQL As New SqlCommand("SELECT * FROM Fighters", conn)
conn.Open()
Dim rstData = New DataTable
rstData.Load(cmdSQL.ExecuteReader)
GridView1.DataSource = rstData
GridView1.DataBind()
End Using
End Using
End Sub
And now I get this:

ASP.NET bound hyperlink as SQL Server stored procedure parameter?

I've currently got a gridview that is populated with summary data. I've created a hyperlink from a bound field labeled ticket_num. What I'm wanting to accomplish is to click the hyperlink and have that call a stored procedure. I need to pass that text of that hyperlink into the stored procedure in SQL Server. So the flow is something like this...
User clicks link
The text of that hyperlink is passed into a parameter for the SQL Server stored procedure to use
Call the stored procedure and display results on new page
Any ideas? The stored procedure is created, connection into the server via ASP.NET is created. Everything works thus far but I can't figure this piece of it out.
Well, since you want some code to execute, then LITTLE reason exists to use a hyper-link, since that not what you need nor want.
You don't mention if you prefer to "hide" the URL and hyper link anyway? (often for security, this is not all such a bad idea).
so, if you need to hide/not show/don't want the value in the grid, then our simple button click can get the row id of the grid (also hidden), and then get the value, and then pass to sql server.
Or, you can add to the button the URL or value to the button - just use command argument. That way you don't have to hit the database again based say on row PK id.
So, here is a simple grid. I have the URL as a row on the grid, but lets also shove/put it into the button for you to see how this works.
So, simple grid:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataKeyNames="ID" CssClass="table" >
<Columns>
<asp:BoundField DataField="Fighter" HeaderText="Fighter" />
<asp:BoundField DataField="Engine" HeaderText="Engine" />
<asp:BoundField DataField="Thrust" HeaderText="Thrust" />
<asp:BoundField DataField="Description" HeaderText="Description" />
<asp:TemplateField HeaderText="Preview">
<ItemTemplate>
<asp:Image ID="Image2" runat="server" ImageUrl = '<%# Eval("ImagePath") %>' Width="140" />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="View">
<ItemTemplate>
<asp:Button ID="cmdView" runat="server" Text="View" CssClass="btn"
CommandArgument = '<%# Eval("ImagePath") %>' OnClick="cmdView_Click" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
And our code to load up the above:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
LoadGridF()
End If
End Sub
Sub LoadGridF()
Using conn As New SqlConnection(My.Settings.TEST4)
Using cmdSQL As New SqlCommand("SELECT * FROM Fighters", conn)
conn.Open()
Dim rstData = New DataTable
rstData.Load(cmdSQL.ExecuteReader)
GridView1.DataSource = rstData
GridView1.DataBind()
End Using
End Using
End Sub
And now we have this:
Note how we have a PLAIN JANE button - after all, it not really a hyper link we need, is it?
So, for our button click event, we have this:
Protected Sub cmdView_Click(sender As Object, e As EventArgs)
Dim btn As Button = sender
Dim gRow As GridViewRow = btn.NamingContainer
Debug.Print("Row index click = " & gRow.RowIndex)
' get database row PK id
Dim iPK As Integer = GridView1.DataKeys(gRow.RowIndex).Item("ID")
' now we have database row PK - walk the dog, do payroll processing
' do ANYTHING we want like get the database row etc.
Debug.Print("Data base row PK id = " & iPK)
Debug.Print("Command button arugment = " & btn.CommandArgument)
End Sub
And output is then:
So, you can see, we did not need (or want a hyper link), but a simple button, and that click event can:
get any value from the given grid row
get the database PK id (hidden - never exposed to client side (good security).
get the row click index
get parameters passed to button
And we can use gRows.Cells() to get the other row values (for data fields)
And of course gRow.FindControl("ctrl name") for templated columns.

How to edit the data shown in a grid view from a SQL database

I made a search function using Grid View, the program reads the user input and based on that it returns the data that matches from the data base, however it returns the whole line, which includes 2 ID columns which I don't want to show. Sounds like something simple yet I can't seem to find any kind of tutorial on how to do this.
Also, the second column IdCargo (IdProfession, in english), I'd like to translate this data, as in, if a specific ID is supposed to appear I would like to instead show the profession of said employee. I would also like to show the column with "Cargo" name instead of "IdCargo", also instead of "CargaHoraria" I want to show "Carga Horaria".
If anyone knows any kind of guide or tutorial with using GridViews and SQL, that would be extremely helpful for future research as well.
Great. Ok, we don't have to worry to much about the search part- I'll assume you enter some search, with parameters, the result is a data table.
Now, I will STRONG suggest that you consider a listview in place of the grid view.
As for controlling which columns? Well, you can template each column. (and that's why I suggest list view - it is less markup).
However, I don't have too many columns - so a GV is "ok", but as you want more columns, more custom layout - then the LV will be LESS markup.
And another REALLY big advantage of LV, is you can get it to write the markup for you.
Anyway, ok, this is our GV.
VERY important:
We have a PK primary key for each row ("ID"). And we of course don't want to show or display that PK ID, but as we all know, a PK is the lifeblood of any data system. So, there is a VERY cool feature in GV - called DataKeys. It allows you to use/have/play the PK row id, but NEVER do you have to expose or display it in the GV. (so not only nice from UI point of view, also VERY nice from a security point of view).
So, say we have this GV layout:
<div style="width:40%;padding:25px">
<style> .borderhide input {border:none}</style>
<asp:GridView ID="GVPeople" runat="server" AutoGenerateColumns="False"
DataKeyNames="ID" cssclass="table borderhide">
<Columns>
<asp:TemplateField HeaderText="First Name">
<ItemTemplate>
<asp:TextBox ID="FirstName" runat="server" Text='<%# Eval("FirstName") %>' ></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Last Name">
<ItemTemplate>
<asp:TextBox ID="LastName" runat="server" Text='<%# Eval("LastName") %>' ></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="City">
<ItemTemplate>
<asp:TextBox ID="City" runat="server" Text='<%# Eval("City") %>' ></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Active" ItemStyle-HorizontalAlign="Center">
<ItemTemplate>
<asp:CheckBox ID="Active" runat="server"
Checked='<%# Eval("Active") %>'/>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Hotel ID">
<ItemTemplate>
<asp:TextBox ID="Hotel_ID" runat="server" Text='<%# Eval("Hotel_ID") %>' ></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
And we will feel this GV with data - MANY more columns exist - but we don't care.
so, my code so far is this:
Dim rstData As New DataTable
Dim rstHotels As New DataTable ' for combo box
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
LoadGrid()
ViewState("rstData") = rstData
Else
rstData = ViewState("rstData")
End If
End Sub
Sub LoadGrid()
rstHotels = MyRst("SELECT ID, HotelName from tblHotels ORDER BY HotelName")
rstData = MyRst("SELECT * from People Order by FirstName")
GVPeople.DataSource = rstData
GVPeople.DataBind()
End Sub
So now we have this:
Ok, so your one part of the question is we obvious don't want to show the Hotel_id, but want to translate it to a description. And of course, if we going to allow edits, then lets convert the Hotel_ID to a combo box (drop down list). And like near most/all combo box, we will store the PK id of the hotel, but of course display the Hotel name for ease of use.
So, in place of hotel_id, we change our markup to this:
<asp:TemplateField HeaderText="Hotel ID">
<ItemTemplate>
<asp:DropDownList ID="cboHotel" runat="server"
DataTextField="HotelName"
DataValueField="ID">
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
Ok, so now we have to fill + setup the combo box. We have TWO tasks:
Fill the combo box with a data source
Set the combo box to the CURRENT selection for each gv row.
For this, we will use the GV row data bound event.
So, our code to fill out the combo will look like this:
So we have this code:
Protected Sub GVPeople_RowDataBound(sender As Object, e As GridViewRowEventArgs) Handles GVPeople.RowDataBound
If e.Row.RowType = DataControlRowType.DataRow Then
' get full row of data bind - all columns
Dim gData As DataRowView = e.Row.DataItem ' NOT A GRID VIEW ROW!!!!!
' get combo box
Dim cboHotels As DropDownList = e.Row.FindControl("cboHotel")
' setup cbo data source
cboHotels.DataSource = rstHotels
cboHotels.DataBind()
cboHotels.Items.Insert(0, New ListItem("", "")) ' add blank (no choice)
If IsDBNull(gData("Hotel_id")) = False Then
cboHotels.SelectedValue = gData("Hotel_ID").ToString
End If
End If
End Sub
so, now our results are this:
Ok, so that takes care of one of your questions/issues.
Next up is to edit - and this is REALLY cool, and REALLY easy.
Ok, if you look close, I "hide" the borders for the text boxes, but you find now that you can tab around quite much like excel. And a nice free-bee is that when text boxes have focus, they show!!
So lets drop in our button below the grid to save edits. It looks like this when I tab around:
Quite much like magic - you can now tab around - almost like Excel. And you can choose combo box value.
And in above, we dropped in a simple button below the GV like this:
</asp:GridView>
<asp:Button ID="cmdSave" runat="server" Text="Save Edits" CssClass="btn" />
Ok, so now the save data button.
We will write one helper routine. There is a BOATLOAD of reasons to split this code into two routines. So the first routine?
It will send the grid values BACK to our table. If you look close, I persisted the GV table data source as rstData.
So this routine sends grid back to table.
Sub GridToTable()
' pull GV rows back to table.
For Each gRow As GridViewRow In GVPeople.Rows
' Get database PK value
Dim PK As Integer = GVPeople.DataKeys(gRow.RowIndex).Item("ID")
Dim OneDataRow As DataRow = rstData.Select("id = " & PK)(0)
OneDataRow.Item("FirstName") = CType(gRow.FindControl("FirstName"), TextBox).Text
OneDataRow.Item("LastName") = CType(gRow.FindControl("LastName"), TextBox).Text
OneDataRow.Item("City") = CType(gRow.FindControl("City"), TextBox).Text
OneDataRow.Item("Active") = CType(gRow.FindControl("Active"), CheckBox).Checked
' combo box
Dim cboHotel As DropDownList = gRow.FindControl("cboHotel")
If cboHotel.Text = "" Then
OneDataRow("Hotel_ID") = DBNull.Value
Else
OneDataRow("Hotel_ID") = cboHotel.SelectedItem.Value
End If
Next
End Sub
Ok, so now all we have to do is send the rstData table (and get this: this will handle NEW rows, or edits!!!!).
so, now our save button code looks like this:
Protected Sub cmdSave_Click(sender As Object, e As EventArgs) Handles cmdSave.Click
GridToTable()
Using conn As New SqlConnection(My.Settings.TEST4)
Using cmdSQL As New SqlCommand("SELECT * from People where ID = 0", conn)
Dim da As New SqlDataAdapter(cmdSQL)
Dim daC As New SqlCommandBuilder(da)
conn.Open()
da.Update(rstData)
End Using
End Using
End Sub
So note how we send the WHOLE grid back to the database, and all changes in ONE shot.
Last but not least:
I used a helper routine to get a data table (became REAL fast typing that kind of code over and over, so I have this and I made it global to the whole application:
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)
rstData.TableName = strSQL
End Using
End Using
Return rstData
End Function
NOTE very carefull, I also STUFF the sql statement into the rst.Table name. Table name not really used, but now since I persisted the SQL for that table?
Then in fact this line
Using conn As New SqlConnection(My.Settings.TEST4)
Using cmdSQL As New SqlCommand("SELECT * from People where ID = 0", conn)
becomes:
Using conn As New SqlConnection(My.Settings.TEST4)
Using cmdSQL As New SqlCommand(rstData.TableName, conn)
What this means is that if/when I have say a child master, or multiple tables of data to edit on a page? I use a dataset (a colleciton of tables), adn have ONE routien to send all tables and all edits back to the database in one shot/routine. We don't have more then one table of data to edit, but this explains why I shove in the SQL statement into the data table "table" name, since as you can see, then we don't even have to re-type the sql used.
NOTE FYI:
That sql statement I used of:
SELECT * from People WHERE ID = 0
Was NOT a type-o. I used that to allow sqlCommandBuilder to do all the dirty work of wiring up and creating the sql insert and update steaments for me.

How to Bind dynamic Data of objects in vb .net or on .aspx page?

I have a Table of Subject Marks and it is dynamic , I want to bind this data on my .aspx page and also want to save or edit these data into database from the page .
Table : SubjectMarks
Subject Marks
English 70
Math 80
Science 90
History 60
I want to save on the page like :
English
70 will be in textbox here
Math
80
Science
90
History
60
I can change the marks data from the textboxes and save the update ones into databse.
Please help me to find this stuff in asp.net. I have .aspx page and backend in .vb
Ok, there are MANY ways to do this.
And you can even use/get the wizards to wire up editing for you. However, I find the built in template editing system REALLY messy to work with.
Having come from desktop land (VB6, ms-access, foxpro), then I want to NOT have to write whacks of code, and I want mostly a drag + drop like easy experience.
So, how to edit some marks for a student that is taking some classes?
Well, I would assume in our database we have Students and StudentCourse table.
(lets keep this simple!)
So, say we have this:
Ok, so we need a combo box to select a student, and then display their courses.
So, first would be say a simple combo box (dropdown) to select a student.
Then we could display the courses, and let you edit the marks. And then an easy save button to save our edits.
Ok, so lets drop in the drop down (combo box). To select the student, and then drop in a gridview for the courses (for display and edit).
And then let’s drop in a button (for saving the edits).
In fact, in place of gridview, lets use a listview. They are VERY similar, but I like listview more since it allows use of standard controls being dropped into the grid display with LESS mess then the gridview. (but, either choice works – I just like the listview better. And it has FAR more customizing abilities. So time spent learning the lv is well worth it.
So, we have this simple markup:
<div style="margin:20px">
<asp:Label ID="Label1" runat="server" Text="Select Student: " Font-Size="Large"></asp:Label>
<asp:DropDownList ID="cboStudents" runat="server" Style="font-size:large;width:180px;margin-left:5px"
AutoPostBack="true"
DataTextField = "FullName"
DataValueField ="ID">
</asp:DropDownList>
<br />
<br />
<div style="width:25%;border:solid;border-width:thin">
<style> input {border:none}</style>
<asp:ListView ID="LstMarks" runat="server" DataKeyNames="ID" >
<ItemTemplate>
<tr style="">
<td><asp:Textbox ID="Course" runat="server" Text='<%# Eval("Course") %>' /></td>
<td><asp:Textbox ID="Mark" runat="server" Text='<%# Eval("Mark") %>' Width="30px"/></td>
<td>
<asp:CheckBox ID="DoneLabs" runat="server" Checked = '<%# Eval("DoneLabs") %>' Width="30px"/>
</td>
</tr>
</ItemTemplate>
<LayoutTemplate>
<table id="itemPlaceholderContainer" runat="server" border="0" class="table">
<tr runat="server" style="">
<th runat="server" >Course</th>
<th runat="server">Mark</th>
<th runat="server" >Completed Lab Work</th>
</tr>
<tr id="itemPlaceholder" runat="server">
</tr>
</table>
</LayoutTemplate>
</asp:ListView>
</div>
<br />
<asp:Button ID="cmdSave" runat="server" Text="Save" class="btn"/>
<asp:Button ID="cmdAdd" runat="server" Text="Add Course" class="btn" Style="margin-left:20px" />
<asp:Button ID="cmdUndo" runat="server" Text="Undo Edits" class="btn" Style="margin-left:20px" />
</div>
Ok, so lets write code to fill up that combo box.
In Project Settings, we add the database connection string here:
(it puts in in web config for you - but this way is OH so much easy - and you get to use the connection string builder).
Ok, so now lets write code to load up the combo box
we have this:
Dim rstMarks As New DataTable
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
cboStudents.DataSource =
MyRst("SELECT *, FirstName + ' ' + LastName AS FullName from Students ORDER BY FirstName")
cboStudents.DataBind()
cboStudents.Items.Insert(0, "")
Else
rstMarks = ViewState("MyMarks")
End If
End Sub
So in above, we load up our combo box, and we ALSO have a table for the marks table (and we persisted the rstMarks table - since we need it for editing).
Ok, so we select a student, and fill the list view.
That code looks like this:
Protected Sub cboStudents_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cboStudents.SelectedIndexChanged
LoadMarks()
End Sub
Sub LoadMarks()
Dim strSQL As String
strSQL = "SELECT * from StudentCourses WHERE Student_ID = " & cboStudents.SelectedValue &
" ORDER BY Course"
rstMarks = MyRst(strSQL)
LstMarks.DataSource = rstMarks
LstMarks.DataBind()
ViewState("MyMarks") = rstMarks
End Sub
Our output is now this:
So you can now tab around, set the course name, mark, and I tossed in for fun a check box for having completed "lab" work.
So, now we need our save button code. After the user tabs around, edits any mark, or changes a check box, we have to send the edits back to the database.
That code looks like this:
Protected Sub cmdSave_Click(sender As Object, e As EventArgs) Handles cmdSave.Click
GridToTable()
SaveToDB()
End Sub
Sub GridToTable()
' move grid edits back to table.
For Each gRow As ListViewItem In LstMarks.Items
Dim OneRow As DataRow = rstMarks.Rows(gRow.DataItemIndex)
OneRow("Course") = CType(gRow.FindControl("Course"), TextBox).Text
OneRow("Mark") = CType(gRow.FindControl("Mark"), TextBox).Text
OneRow("DoneLabs") = CType(gRow.FindControl("DoneLabs"), CheckBox).Checked
Next
End Sub
Sub SaveToDB()
Using cmdSQL As New SqlCommand("SELECT * FROM StudentCourses WHERE ID = 0",
New SqlConnection(My.Settings.TEST4))
Dim da As New SqlDataAdapter(cmdSQL)
Dim daSQL As New SqlCommandBuilder(da)
da.Update(rstMarks)
End Using
End Sub
So what the above does? It moves grid values back to the table.
THEN Sends the data table (with edits, or even new rows added) back to the database.
And that is quite much it.
I tossed in a add course button, and code for that is this:
Protected Sub cmdAdd_Click(sender As Object, e As EventArgs) Handles cmdAdd.Click
GridToTable() ' user might have made edits - send them to table
' add a new row to table
Dim OneRow As DataRow = rstMarks.NewRow
OneRow("Student_ID") = cboStudents.SelectedItem.Value
OneRow("DoneLabs") = False
OneRow("Mark") = 0
rstMarks.Rows.Add(OneRow)
LstMarks.DataSource = rstMarks ' send table to grid
LstMarks.DataBind()
End Sub
And I did create a helper routine to get data into a table, and that code was:
Function MyRst(strSQL As String) As DataTable
Dim rstData As New DataTable
Using cmdSQL As New SqlCommand(strSQL, New SqlConnection(My.Settings.TEST4))
cmdSQL.Connection.Open()
rstData.Load(cmdSQL.ExecuteReader)
End Using
Return rstData
End Function
And the un-do edits button? It just re-loads the grid without saving, and thus is this:
Protected Sub cmdUndo_Click(sender As Object, e As EventArgs) Handles cmdUndo.Click
LoadMarks()
End Sub
(it just does the SAME thing as selecting a student in the combo box.
So, the above is FULL of great ideas on how to do this.
And really, it not a lot of code, and you can quite much use the above approach for just about any kind of data editing you need.

How do I assign OnRowCommand to multiple IDs ASP.net and VB.net Backend

I have 2 GridViews with separate IDs
I need the backend code to update the one being viewed when a button is clicked.
` Protected Sub savestatus(sender As Object, e As EventArgs)
Dim btn As Button = TryCast(sender, Button)
Dim row As GridViewRow = CType(((CType(sender, Button)).NamingContainer), GridViewRow)
Dim rowindex As Integer = row.RowIndex
Dim code As String = GridView1.DataKeys(row.RowIndex).Values(0).ToString()
Dim type As Int32 = GridView1.DataKeys(row.RowIndex).Values(1)
Dim statusid As Integer
Dim checkLocked, checkerror As CheckBox
' For Each row As GridViewRow In GridView1.Rows
checkLocked = CType(GridView1.Rows(rowindex).FindControl("lock"), CheckBox)
checkerror = CType(GridView1.Rows(rowindex).FindControl("error"), CheckBox)
If checkerror.Checked Then ' error
statusid = 2
End If
If checkLocked.Checked Then
statusid = 3
End If`
How do I make the GridView1 a variable depending on which grid view the button is pressed in.
Ok, it would have helped a lot to at least show the button and a few rows of the gridview markup.
There are about 10 ways to do this. (really !!!).
However, in your case, two check boxes, and you need actions to occur when a check box is changed – AND say change the other one!!
Now I am using two check boxes – but it could be a text box or whatever I change.
So, say I have this grid markup
Some columns + TWO un-bound check boxes.
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="false">
<Columns>
<asp:BoundField DataField="ID" HeaderText="ID" />
<asp:BoundField DataField="HotelName" HeaderText="HotelName" />
<asp:BoundField DataField="City" HeaderText="City" />
<asp:BoundField DataField="Province" HeaderText="Province" />
<asp:TemplateField HeaderText="Good">
<ItemTemplate>
<asp:CheckBox ID="chkGood" runat="server"
AutoPostBack="true"
OnCheckedChanged="chkGood_CheckedChanged"
MyRowID ='<%# Container.DataItemIndex %>' />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Bad">
<ItemTemplate>
<asp:CheckBox ID="chkBad" runat="server"
AutoPostBack="true"
OnCheckedChanged="chkBad_CheckedChanged"
MyRowID ='<%# Container.DataItemIndex %>' />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Ok, and now the code to load the grid:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If IsPostBack = False Then
Using cmdSQL As New SqlCommand("SELECT ID, HotelName, City, Province from tblHotels",
New SqlConnection(My.Settings.Test3))
cmdSQL.Connection.Open()
GridView1.DataSource = cmdSQL.ExecuteReader
GridView1.DataBind()
End Using
End If
End Sub
And thus we have this:
Ok, so far - very simple.
Now note CLOSE at the markup for the two check boxes.
And while dropping a button or whatever on a normal form - you can then double click to JUMP to the code behind event/stub?
Well, for buttons or whatever you drop INSIDE of a grid, you can't double click on the control to create + jump to the code behind stub.
But, WHILE in the markup, you can start typing the event, and you get this:
Note VERY careful how the intel-sense pops up a option to create the event. So click on that option. Nothing seems to happen, but NOW we get a code stub behind.
So, we have this code stub for the chkOk event:
Protected Sub chkGood_CheckedChanged(sender As Object, e As EventArgs)
Dim ckBox As CheckBox = sender
Dim RowID As Integer = ckBox.Attributes.Item("MyRowID")
Dim gvRow As GridViewRow = GridView1.Rows(RowID)
If ckBox.Checked = True Then
' do whatever if true - say un-check the "bad" check box
Dim ckBoxBad As CheckBox = gvRow.FindControl("chkBad")
ckBoxBad.Checked = False
Else
' code here if the user just un-checked the "good" check box
End If
End Sub
Note a few things:
We pick up the button click - then shove it into a checkbox control. This is just a lot easier to get the check box value, and our CUSTOM MyRowID
(and this works if it was a button for example).
We then get the custom made up Attribute we added called "MyRowID"
MyRowID ='<%# Container.DataItemIndex %>'
You can see the expression in the Markup - it passes the current row id. Sometimes, I'll pass other values from the row and you can do this like this:
<asp:CheckBox ID="chkBad" runat="server"
AutoPostBack="true"
OnCheckedChanged="chkBad_CheckedChanged"
MyRowID ='<%# Container.DataItemIndex %>'
MyPKID = '<%# Eval("ID") %>' />
So in above, I pass both RowID and a custom MyPKID (so the Eval() expression can be used to pass any valid data row avaialble at binding time. Its often handy then having to grab and mess with a data row - you JUST grab the button from sender - and you don't care about gridview or anything else to get a few extra values. (just a FYI tip). So for example, I REALLY don't want the PK row id as the first row. So I could remove it and STILL use the above idea to PASS the pk row id - all columns can be used - even if a control is NOT in the grid - as long as the column exists during the data binding process - you can grab it.
So, now we pick up the current GridRow - and we are free to modify whatever we want on that row.
In my simple example, we pick up the OTHER check box - and un-check if it was checked. But we could say update other things on that row.
And I did the same for the chkBad check box. And I have really the same as the first chkBox code stub. Eg this:
Protected Sub chkBad_CheckedChanged(sender As Object, e As EventArgs)
Dim ckBox As CheckBox = sender
Dim RowID As Integer = ckBox.Attributes.Item("MyRowID")
Dim gvRow As GridViewRow = GridView1.Rows(RowID)
If ckBox.Checked = True Then
' user checked the bad box, un-check the good one
Dim ckBoxGood As CheckBox = gvRow.FindControl("chkGood")
ckBoxGood.Checked = False
Else
' code here if the user just un-checked the "bad" check box
End If
End Sub
So in above we just hard right past the GridView bult in events.
So in above, if you check one box and the other is checked - we un-check it. Needless to say, I would use a button list, or a checkbox list, and that above code would of course then not be required. But it still a good example on how to pluck/get the current row. And then get/pluck controls from that row.
Note that for the first 3 rows (the databound), you can NOT use findControl, and they are referenced using the gvRow.Cells(0) (starting at 0 to N columns. So no findcontrol is required for these databound columns or autogenerated ones. They do NOT have a name - you have to use number starting at 0 in the cells collection. Of course for "templated" controls that we added as per above? Then you do in fact use findcontrol as per above.

Resources