asp:Gridview getting focused column/lifecycle issue - asp.net

I am working on a proof of concept (POC) GridView for a much more complex set of functionality where any given cell is filled with a textbox whether it is in normal or edit mode. When any given textbox receives focus (tab or mouse), the row is set to an edit state and it's corresponding textbox in edit mode should receive focus. Once that textbox loses focus it should cause an update on that row. I have the POC working except finding a viable way to select the column ("textbox") that received focus which I believe is a lifecycle issue, but am not coming up with any good workarounds. Please remember this is a POC and there are things I have done that may not be best practice as a quick and dirty way to get it working. I would greatly appreciate any suggestions.
Form:
<%# Page Language="vb" AutoEventWireup="false" CodeBehind="StandardContactEditor.aspx.vb" Inherits="EditableGridView.StandardContactEditor" EnableEventValidation="false" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:GridView ID="contactsDataGrid"
AllowPaging="true" PageSize="5"
DataKeyNames="ID"
AutoGenerateColumns="false"
runat="server">
<Columns>
<asp:TemplateField HeaderText="First Name">
<ItemTemplate>
<asp:TextBox ID="txtFirstName" Text='<%# Bind("FirstName") %>' runat="server" />
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox ID="txtFirstNameEdit" Text='<%# Bind("FirstName") %>' runat="server" />
</EditItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Last Name">
<ItemTemplate>
<asp:TextBox ID="txtLastName" Text='<%# Bind("LastName") %>' runat="server" />
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox ID="txtLastNameEdit" Text='<%# Bind("LastName") %>' runat="server" />
</EditItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</div>
</form>
</body>
</html>
Code:
Imports FileHelpers
Public Class StandardContactEditor
Inherits System.Web.UI.Page
private fileName As String = "C:\TestFiles\TestContacts.csv"
Private records As List(Of ContactCSV)
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack
BindGridData()
End If
End Sub
Private Sub BindGridData()
PopulateRecords()
Me.contactsDataGrid.DataSource = records
Me.contactsDataGrid.DataBind()
End Sub
Protected Sub RowDataBound(ByVal sender As Object, ByVal e As GridViewRowEventArgs) Handles contactsDataGrid.RowDataBound
e.Row.Attributes("onfocus") = ClientScript.GetPostBackClientHyperlink(contactsDataGrid, "Edit$" + e.Row.DataItemIndex.ToString(), false)
If Not ((e.Row.RowState = DataControlRowState.Edit) _
Or (e.Row.RowState = (DataControlRowState.Alternate Or DataControlRowState.Edit)))
Try
' First Name Column
Dim firstNameTb As TextBox = e.Row.FindControl("txtFirstName")
' firstNameTb.Attributes("onfocus") = ClientScript.GetPostBackClientHyperlink(contactsDataGrid, "Edit$" + e.Row.DataItemIndex.ToString(), false)
' ISSUE CAUSED BY APPENDING "000" - Used for col/textbox identification
firstNameTb.Attributes("onfocus") = ClientScript.GetPostBackClientHyperlink(contactsDataGrid, "Edit$" + e.Row.DataItemIndex.ToString() + "000", false)
Catch ex As Exception
Console.WriteLine()
End Try
Try
Dim lastNameTb As TextBox = e.Row.FindControl("txtLastName")
' lastNameTb.Attributes("onfocus") = ClientScript.GetPostBackClientHyperlink(contactsDataGrid, "Edit$" + e.Row.DataItemIndex.ToString(), false)
' ISSUE CAUSED BY APPENDING "001" - Used for col/textbox identification
lastNameTb.Attributes("onfocus") = ClientScript.GetPostBackClientHyperlink(contactsDataGrid, "Edit$" + e.Row.DataItemIndex.ToString() + "001", false)
Catch ex As Exception
End Try
End If
End Sub
Protected Sub RowEditing(ByVal sender As Object, ByVal e As GridViewEditEventArgs) Handles contactsDataGrid.RowEditing
contactsDataGrid.EditIndex = (e.NewEditIndex / 1000)
Dim col As Integer = (e.NewEditIndex Mod 1000)
' contactsDataGrid.EditIndex = e.NewEditIndex
BindGridData()
Dim fntb As TextBox = contactsDataGrid.Rows(contactsDataGrid.EditIndex).FindControl("txtFirstNameEdit")
fntb.Attributes("onblur") = ClientScript.GetPostBackClientHyperlink(contactsDataGrid, "Update$" + contactsDataGrid.EditIndex.ToString(), false)
' fntb.Focus()
Dim lntb As TextBox = contactsDataGrid.Rows(contactsDataGrid.EditIndex).FindControl("txtLastNameEdit")
lntb.Attributes("onblur") = ClientScript.GetPostBackClientHyperlink(contactsDataGrid, "Update$" + contactsDataGrid.EditIndex.ToString(), false)
' lntb.Focus()
If(col = 0)
fntb.Focus()
Else If(col = 1)
lntb.Focus()
End If
End Sub
Protected Sub RowUpdating(ByVal sender As Object, ByVal e As GridViewUpdateEventArgs) Handles contactsDataGrid.RowUpdating
' AT THIS POINT THE EDIT FIELDS ARE NOT VISIBLE AND AN EXCEPTION IS THROWN WHEN TRYING TO RETRIEVE THOSE TEXTBOXES
' Trying to override here
contactsDataGrid.EditIndex = (contactsDataGrid.EditIndex / 1000)
PopulateRecords()
Dim id As String = contactsDataGrid.DataKeys(e.RowIndex).Value.ToString()
Dim record As ContactCSV = records.Where(Function(x) x.ID = id).SingleOrDefault()
Dim firstNameTb As TextBox = contactsDataGrid.Rows(e.RowIndex).FindControl("txtFirstNameEdit")
record.firstName = firstNameTb.Text
Dim lastNameTb As TextBox = contactsDataGrid.Rows(e.RowIndex).FindControl("txtLastNameEdit")
record.lastName = lastNameTb.Text
WriteRecordsToFile()
contactsDataGrid.EditIndex = -1
' update the actual data
contactsDataGrid.DataSource = records
contactsDataGrid.DataBind()
End Sub
Protected Sub SelectedColumn(ByVal Sender As Object, ByVal e As EventArgs)
Console.WriteLine()
End Sub
Private Sub PopulateRecords()
Dim fileEngine As New FileHelperEngine(GetType(ContactCSV))
Try
Dim objs As ContactCSV() = fileEngine.ReadFile(fileName)
records = objs.ToList()
Catch ex As exception
End Try
End Sub
Private Sub WriteRecordsToFile()
Dim fileEngine As New FileHelperEngine(GetType(ContactCSV))
fileEngine.WriteFile(fileName, records)
End Sub
End Class

This was a classic case of over-thinking a solution with a combination of an unfamiliar technology. The idea was to build a highly responsive (per field edit) page. Rather than mix any built-in GridView functionality, a simple OnTextChanged worked as I expected after everything else was stripped out. The problem turned out with the previous code posted is after an OnBlur, with the column identification parts in place, a row was set to Alternate state rather than Alternate Or Edit state.
Form:
<%# Page Language="vb" AutoEventWireup="false" CodeBehind="StandardContactEditor.aspx.vb" Inherits="EditableGridView.StandardContactEditor" EnableEventValidation="true" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:GridView ID="contactsDataGrid"
AllowPaging="true" PageSize="5"
DataKeyNames="ID"
AutoGenerateColumns="false"
runat="server">
<Columns>
<asp:TemplateField HeaderText="First Name">
<ItemTemplate>
<asp:TextBox ID="txtFirstName" Text='<%# Bind("FirstName") %>' OnTextChanged="textBox_TextChanged" AutoPostBack="true" runat="server" />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Last Name">
<ItemTemplate>
<asp:TextBox ID="txtLastName" Text='<%# Bind("LastName") %>' OnTextChanged="textBox_TextChanged" AutoPostBack="true" runat="server" />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Phone Number">
<ItemTemplate>
<asp:TextBox ID="txtPhoneNumber" Text='<%# Bind("PhoneNumber") %>' OnTextChanged="textBox_TextCHanged" AutoPostBack="true" runat="server" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</div>
</form>
</body>
</html>
Code:
Imports FileHelpers
Public Class StandardContactEditor
Inherits System.Web.UI.Page
private fileName As String = "C:\TestFiles\TestContacts.csv"
Private records As List(Of ContactCSV)
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack
BindGridData()
End If
End Sub
Private Sub BindGridData()
PopulateRecords()
Me.contactsDataGrid.DataSource = records
Me.contactsDataGrid.DataBind()
End Sub
Protected Sub textBox_TextChanged(ByVal sender As Object, ByVal e As EventArgs)
PopulateRecords()
Dim tb as TextBox = sender
Dim row As GridViewRow = tb.Parent.Parent
Dim record As ContactCSV = records.Where(Function(x) x.ID = row.RowIndex).SingleOrDefault()
Dim firstNameTb As TextBox = contactsDataGrid.Rows(row.RowIndex).FindControl("txtFirstName")
record.firstName = firstNameTb.Text
Dim lastNameTb As TextBox = contactsDataGrid.Rows(row.RowIndex).FindControl("txtLastName")
record.lastName = lastNameTb.Text
Dim phoneNumberTb As TextBox = contactsDataGrid.Rows(row.RowIndex).FindControl("txtPhoneNumber")
record.PhoneNumber = phoneNumberTb.Text
WriteRecordsToFile()
End Sub
Private Sub PopulateRecords()
Dim fileEngine As New FileHelperEngine(GetType(ContactCSV))
Try
Dim objs As ContactCSV() = fileEngine.ReadFile(fileName)
records = objs.ToList()
Catch ex As exception
End Try
End Sub
Private Sub WriteRecordsToFile()
Dim fileEngine As New FileHelperEngine(GetType(ContactCSV))
fileEngine.WriteFile(fileName, records)
End Sub
End Class

Related

Dynamic file download buttons in VB .NET

I have a page in a VB NET 2005 web project. On page load, it takes data from the logged in user, looks up a set of documents owned by that user, and creates a "download" button for each. Currently, this button opens a new window that streams the document, but we'd like the button itself to trigger a download.
I've got some options for this, but they all seem kind of hacky, and while I haven't found any good solutions, this seems like it should be a solved problem.
The buttons are in a form (so postback with hidden fields is one of the "hacky" options).
Let's say I have a GridView with 3 columns: Filename, Size and a Download button. Then set the CommandName and CommandArgument of the button. For security reason, it might be a better idea to use the user's document id instead of the full path name like I did. You can get the real file using combination of current user and the document id.
<asp:TemplateField HeaderText="Filename">
<ItemTemplate>
<asp:Label ID="lblFilename" runat="server" Text='<%# Bind("Filename") %>' />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Size">
<ItemTemplate>
<asp:Label ID="lblSize" runat="server" Text='<%# Bind("Size") %>' />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Download">
<ItemTemplate>
<asp:Button ID="btnDownload" runat="server" Text="Download"
CommandName="Download" CommandArgument='<%# Eval("FullName") %>' />
</ItemTemplate>
</asp:TemplateField>
This is the class which I use to hold the list of files for download. A list of this class binds to the GridView.
Public Class MyFileInfo
Public Property Filename As String
Public Property Fullname As String
Public Property Size As Long
End Class
Last is handling the Download button click. I use the CommandName and CommandArgument to pass what button is click and what file it needs to give to the browser. I use stream and write to the browser with proper MIME type in the header.
Protected Sub GridView1_RowCommand(sender As Object, e As GridViewCommandEventArgs) Handles GridView1.RowCommand
If e.CommandName = "Download" Then
DownloadFile(e.CommandArgument)
End If
End Sub
Sub DownloadFile(filename As String)
Using fs = New FileStream(filename, FileMode.Open)
Response.BufferOutput = False
Response.AddHeader("Content-Length", fs.Length.ToString())
Response.AppendHeader("Content-Disposition", "attachment;filename=" & Path.GetFileName(filename))
Response.ContentType = "application/msword"
fs.Position = 0
fs.CopyTo(Response.OutputStream)
Response.Flush()
Response.End()
End Using
End Sub
Full code (aspx):
<%# Page Language="vb" AutoEventWireup="false" CodeBehind="WebForm1.aspx.vb" Inherits="WebApplication1.WebForm1" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False">
<Columns>
<asp:TemplateField HeaderText="Filename">
<ItemTemplate>
<asp:Label ID="lblFilename" runat="server" Text='<%# Bind("Filename") %>' />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Size">
<ItemTemplate>
<asp:Label ID="lblSize" runat="server" Text='<%# Bind("Size") %>' />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Download">
<ItemTemplate>
<asp:Button ID="btnDownload" runat="server" Text="Download"
CommandName="Download" CommandArgument='<%# Eval("FullName") %>' />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</div>
</form>
</body>
</html>
Full code (code behind):
Imports System.IO
Public Class WebForm1
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then BindGridList()
End Sub
Protected Sub GridView1_RowCommand(sender As Object, e As GridViewCommandEventArgs) Handles GridView1.RowCommand
If e.CommandName = "Download" Then
DownloadFile(e.CommandArgument)
End If
End Sub
Sub BindGridList()
GridView1.DataSource = GetFiles()
GridView1.DataBind()
End Sub
Function GetFiles() As List(Of MyFileInfo)
Dim listFileInfos = New List(Of MyFileInfo)
Dim dirInfo = New DirectoryInfo(Server.MapPath("~/Data"))
Dim fileInfos = dirInfo.GetFiles("*.doc")
For Each fileInfo In fileInfos
listFileInfos.Add(New MyFileInfo With {.Filename = fileInfo.Name, .Size = fileInfo.Length, .Fullname = fileInfo.FullName})
Next
Return listFileInfos
End Function
Sub DownloadFile(filename As String)
Using fs = New FileStream(filename, FileMode.Open)
Response.BufferOutput = False
Response.AddHeader("Content-Length", fs.Length.ToString())
Response.AppendHeader("Content-Disposition", "attachment;filename=" & Path.GetFileName(filename))
Response.ContentType = "application/msword"
fs.Position = 0
fs.CopyTo(Response.OutputStream)
Response.Flush()
Response.End()
End Using
End Sub
End Class
Public Class MyFileInfo
Public Property Filename As String
Public Property Fullname As String
Public Property Size As Long
End Class

ListView Datapager not working When Session used instead of VeiwState

I want to display list of clinics details in listview. From MasterPage Users selects the city & If he goes to clinincs page then list of hospitals display from selected city. Now If I use ViewState in my clinics page then It does not gets clinics data from selected city So what I have done I store City session & on clinics page I have used Session instead of ViewState Which is now working right but my datagaer stopped working. If I have to see another page from datapager then it doesn't switch over. Here is my code
MasterPage
Protected Sub locationSelector_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles locationSelector.TextChanged
Session("masterLocation") = locationSelector.text
Session("Data") = Nothing
End Sub
Clinics Page
Private Sub hospitals_PreRender(sender As Object, e As EventArgs) Handles Me.PreRender
Try
If Not Session("Data") Is Nothing Then
hospitals.DataSource = Session("Data")
hospitals.DataBind()
Else
Dim citySelector As Label = Page.Master.FindControl("locationPopupActivator")
query = "select hospitalid, name, address, thumbnail, serviceID, mondayFrom, mondayTo, consultancyFees, city from hospitals Where city Like '" + citySelector.Text + "%' and status = 'active'"
Dim cmd As New MySqlCommand(query, con)
cmd.CommandTimeout = 120
Dim da As New MySqlDataAdapter(cmd)
Dim table As New DataTable
da.Fill(table)
Session("Data") = table
hospitals.DataSource = table
hospitals.DataBind()
End If
'mainCount.Text = table.Rows(0)("countRows").ToString
Catch ex As Exception
Response.Write(ex)
End Try
End Sub
Protected Sub DataPager1_PreRender(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreRender
Try
Dim table As DataTable = Session("Data")
hospitals.DataSource = table
hospitals.DataBind()
Catch ex As Exception
Response.Write(ex)
End Try
End Sub
Listview on ASPX
<asp:ListView ID="hospitals" runat="server" DataKeyNames="hospitalID" DataKey="hospitalID">
<ItemTemplate>
My Content
</ItemTemplate>
<EmptyDataTemplate>
<div class="not-found">
<p>
Sorry! Selected Query Not Found</p>
<center>
<img src="images/not-found.jpg" /></center>
</div>
</EmptyDataTemplate>
<LayoutTemplate>
<ul id="itemPlaceholderContainer" runat="server" style="">
<li runat="server" id="itemPlaceholder" />
</ul>
<div class="datapager" style="padding-bottom: 10px;">
<asp:DataPager ID="DataPager1" runat="server" PageSize="10" PagedControlID="hospitals" ViewStateMode="Enabled">
<Fields>
<asp:NextPreviousPagerField ButtonType="Link" ShowFirstPageButton="false" ShowPreviousPageButton="true" ShowNextPageButton="false" />
<asp:NumericPagerField ButtonType="Link" />
<asp:NextPreviousPagerField ButtonType="Link" ShowNextPageButton="true" ShowLastPageButton="false" ShowPreviousPageButton="false" />
</Fields>
</asp:DataPager>
</div>
</LayoutTemplate>
</asp:ListView>
This is working sample of your page:
hospital.master
<%# Master Language="VB" CodeFile="hospital.master.vb" Inherits="hospital_master" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<asp:ContentPlaceHolder ID="head" runat="server">
</asp:ContentPlaceHolder>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="sm" runat="server" />
<div>
<asp:Label ID="lblLockSel" runat="server" AssociatedControlID="locationSelector">Locator Selector</asp:Label>
<asp:UpdatePanel ID="upLocSel" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:TextBox ID="locationSelector" runat="server" AutoPostBack="true"></asp:TextBox>
<asp:Label ID="locationPopupActivator" runat="server"></asp:Label>
</ContentTemplate>
</asp:UpdatePanel>
<asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
</asp:ContentPlaceHolder>
</div>
</form>
</body>
</html>
hospital.master.vb
Partial Class hospital_master
Inherits System.Web.UI.MasterPage
Protected Sub locationSelector_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles locationSelector.TextChanged
Session("masterLocation") = locationSelector.Text
Session("Data") = Nothing
locationPopupActivator.Text = locationSelector.Text
End Sub
End Class
clinics.aspx
<%# Page Title="" Language="VB" MasterPageFile="~/hospital.master" AutoEventWireup="false" CodeFile="clinics.aspx.vb" Inherits="Clinics" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
<asp:UpdatePanel ID="upHospitals" runat="server" UpdateMode="Always">
<ContentTemplate>
<asp:ListView ID="hospitals" runat="server" DataKeyNames="hospitalID" DataKey="hospitalID">
<ItemTemplate>
<%--My Content--%>
<li>
<asp:HyperLink ID="lnkHospital" runat="server" NavigateUrl='<%#Eval("hospitalID", "~/hospital.aspx?id={0}") %>' Text='<%#Eval("Name") %>'></asp:HyperLink>
</li>
</ItemTemplate>
<EmptyDataTemplate>
<div class="not-found">
<p>
Sorry! Selected Query Not Found</p>
<center><%--<center>Is Deprecated Use div with CSS</center>--%>
<img src="images/not-found.jpg" /></center>
</div>
</EmptyDataTemplate>
<LayoutTemplate>
<ul>
<li runat="server" id="itemPlaceholder" />
</ul>
</LayoutTemplate>
</asp:ListView>
<%--Inside Update Panel dataPager should be outside paged control--%>
<div class="datapager" style="padding-bottom: 10px;">
<asp:DataPager ID="DataPager1" runat="server" PageSize="10" PagedControlID="hospitals"><%-- ViewStateMode="Enabled"> this is default--%>
<Fields>
<asp:NextPreviousPagerField ButtonType="Link" ShowFirstPageButton="false" ShowPreviousPageButton="true" ShowNextPageButton="false" />
<asp:NumericPagerField ButtonType="Link" />
<asp:NextPreviousPagerField ButtonType="Link" ShowNextPageButton="true" ShowLastPageButton="false" ShowPreviousPageButton="false" />
</Fields>
</asp:DataPager>
</div>
</ContentTemplate>
</asp:UpdatePanel>
</asp:Content>
clinics.aspx.vb
Partial Class Clinics
Inherits System.Web.UI.Page
Private Sub Clinics_Load(sender As Object, e As EventArgs) Handles Me.Load
If Not Page.IsPostBack Then
Session.Remove("Data") 'init
End If
End Sub
Private Sub hospitals_PagePropertiesChanging(sender As Object, e As PagePropertiesChangingEventArgs) Handles hospitals.PagePropertiesChanging
DataPager1.SetPageProperties(e.StartRowIndex, e.MaximumRows, False)
hospitals.DataSource = GetData() 'Session("Data")
hospitals.DataBind()
End Sub
Private Sub hospitals_PreRender(sender As Object, e As EventArgs) Handles Me.PreRender
hospitals.DataSource = GetData()
hospitals.DataBind()
End Sub
Private Function GetData() As Data.DataTable
Try
If Session("Data") IsNot Nothing Then
Return Session("Data")
Else
'This is MS SQL server. If you use MySQL then change types accordingly
DataPager1.SetPageProperties(0, DataPager1.PageSize, False) 'reinit
Dim citySelector As Label = Page.Master.FindControl("locationPopupActivator")
Using con As New Data.SqlClient.SqlConnection(ConfigurationManager.ConnectionStrings("ClinicsCNN").ConnectionString)
Dim cmd As New Data.SqlClient.SqlCommand("select hospitalid, name, address, thumbnail, serviceID, mondayFrom, mondayTo, consultancyFees, city from hospitals Where city Like #city and status = 'active'", con)
cmd.CommandType = Data.CommandType.Text
cmd.Parameters.Add("#city", Data.SqlDbType.VarChar, 50).Value = citySelector.Text & "%" 'same as Session("masterLocation")
Dim table As New Data.DataTable()
Dim da As New Data.SqlClient.SqlDataAdapter(cmd)
da.Fill(table)
da.Dispose()
cmd.Dispose()
Session("Data") = table
Return table
End Using
End If
Catch ex As Exception
Response.Write(ex) 'for debug purpose
Return Nothing
End Try
End Function
End Class
Do you accept this solution?
Ok, after your comments here is my code that works for me:
Private Sub hospitals_PreRender(sender As Object, e As EventArgs) Handles Me.PreRender
Try
If Session("Data") Is Nothing Then
Dim citySelector As Label = Page.Master.FindControl("locationPopupActivator")
query = "select hospitalid, name, address, thumbnail, serviceID, mondayFrom, mondayTo, consultancyFees, city from hospitals Where city Like '" + citySelector.Text + "%' and status = 'active'"
Dim cmd As New MySqlCommand(query, con)
cmd.CommandTimeout = 120
Dim da As New MySqlDataAdapter(cmd)
Dim table As New DataTable
da.Fill(table)
Session("Data") = table
hospitals.DataSource = table
hospitals.DataBind()
End If
'mainCount.Text = table.Rows(0)("countRows").ToString
Catch ex As Exception
Response.Write(ex)
End Try
End Sub
protected void hospitals_PagePropertiesChanging(object sender, System.Web.UI.WebControls.PagePropertiesChangingEventArgs e)
{
var datapager = ((DataPager)hospitals.FindControl("DataPager1"));
datapager.SetPageProperties(e.StartRowIndex, e.MaximumRows, false);
hospitals.DataSource = Session["Data"];
hospitals.DataBind();
datapager.DataBind();
}
I don't think you need DataPager1_PreRender method at all so probably you should remove it all together. You will need to attach new event to your list view: OnPagePropertiesChanging="hospitals_PagePropertiesChanging". Sorry for code in c#, but I don't know VB very well ;)

Why isn't the new values pulling up when I update the GridViewRow?

So what's happening is that I click the Edit button, type the updated values and hit Update. But the code-behind gets the original values not the updated values. I can't figure out why. It's always worked before.
Markup
<asp:GridView ID="GridView2" runat="server" AutoGenerateColumns="False"
CellPadding="7" ForeColor="#333333" GridLines="None" Font-Size="Small"
ShowFooter="True" DataKeyNames="CapID">
<AlternatingRowStyle BackColor="White" />
<Columns>
<asp:TemplateField HeaderText="AllocationId">
<ItemTemplate>
<asp:Label ID="show" runat="server" Text='<%# Eval("CapID") %>' />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Reference Number">
<ItemTemplate>
<asp:Label ID="showRefNo" runat="server" Text='<%# Eval("RefNo") %>'/>
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox runat="server" ID="EditRefNo"
Text='<%# Bind("RefNo") %>'/>
</EditItemTemplate>
<FooterTemplate>
<asp:TextBox runat="server" ID="InsertRefNo"
Text='<%# Bind("RefNo") %>'/>
</FooterTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Resource">
<ItemTemplate>
<asp:Label ID="showResource" runat="server"
Text='<%# Eval("Resource") %>'/>
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox runat="server" ID="EditResource"
Text='<%# Bind("Resource") %>'/>
</EditItemTemplate>
<FooterTemplate>
<asp:TextBox runat="server" ID="InsertResource"
Text='<%# Bind("Resource") %>'/>
</FooterTemplate>
</asp:TemplateField>
<!-- and so on... -->
</Columns>
<!-- styles etc -->
<EmptyDataTemplate>
Ref Num: <asp:TextBox ID="newRefNo" runat="server"/>
Resource: <asp:TextBox ID="newResource" runat="server"/>
Hours Allocated: <asp:TextBox ID="newHours" runat="server"/>
Week Offset: <asp:TextBox ID="newOffset" runat="server"/>
<asp:Button runat="server" ID="NewDataInsert"
CommandName="NewDataInsert" Text="Insert"/>
</EmptyDataTemplate>
</asp:GridView>
Code Behind
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)
Handles Me.Load
If Not IsPostBack Then
GridView1_DataBind()
GridView2_DataBind()
End If
End Sub
Protected Sub GridView2_RowUpdating(ByVal sender As Object, ByVal e As
GridViewUpdateEventArgs) Handles GridView2.RowUpdating
Dim capID As Label = GridView2.Rows(e.RowIndex).Cells(0)
.FindControl("show")
Dim refNo As TextBox = GridView2.Rows(e.RowIndex).Cells(1)
.FindControl("EditRefNo")
Dim resource As TextBox =
GridView2.Rows(e.RowIndex).Cells(2).FindControl("EditResource")
Dim hours As TextBox =
GridView2.Rows(e.RowIndex).Cells(3).FindControl("EditHours")
Dim offSet As TextBox =
GridView2.Rows(e.RowIndex).Cells(4).FindControl("EditOffset")
Dim newResAlloc As DataTable = resourceInfo.loadResAllocations
Dim updateRows As DataRow() =
newResAlloc.Select("CapID = " & "'" & capID.Text & "'")
If (Not updateRows Is Nothing) And updateRows.Length > 0 Then
For Each updRow As DataRow In updateRows
updRow.BeginEdit()
updRow.Item("Refno") = refNo.Text
updRow.Item("Resource") = resource.Text
updRow.Item("Hours") = hours.Text
updRow.Item("Offset") = offSet.Text
updRow.EndEdit()
Next
End If
resourceInfo.updateResAllocations(newResAlloc)
GridView2.EditIndex = -1
GridView2_DataBind()
End Sub
This could be a million and one things. What have you checked? Have you narrowed it down?
Here's some starting points for you:
Put a breakpoint inside GridView2_RowUpdating to make sure it's being called.
Check the value of capID, or capID.Text - it shouldn't be 0.
Check that your database table contains a row where CapID equals the value of capID.Text
Put a breakpoint on updateRows to ensure that the database row is being loaded into your code.
Make sure that the updRow.EndEdit() is being hit, and that the values are populated into the row correctly.
Finally, check that the updateResAllocations is working properly. It's impossible to see from here how it works, so I can't give any advice on that.
The easiest way to fix this might be to ask whoever wrote it for some assistance.
The problem was that my RowCommand method was calling the DataBind
Wrong way:
Protected Sub GridView2_RowCommand(ByVal sender As Object, ByVal e As GridViewCommandEventArgs) Handles GridView2.RowCommand
If e.CommandName = "NewDataInsert" Then
Dim refNo As TextBox = GridView2.Controls(0).Controls(0).FindControl("NewRefNo")
Dim resource As TextBox = GridView2.Controls(0).Controls(0).FindControl("NewResource")
Dim hours As TextBox = GridView2.Controls(0).Controls(0).FindControl("NewHours")
Dim offset As TextBox = GridView2.Controls(0).Controls(0).FindControl("NewOffset")
Dim newResAlloc As DataTable = resourceInfo.loadResAllocations
Dim newAllocRow As DataRow = newResAlloc.NewRow
newAllocRow.ItemArray = New Object() {Nothing, refNo.Text, resource.Text, hours.Text, offset.Text}
newResAlloc.Rows.Add(newAllocRow)
resourceInfo.updateResAllocations(newResAlloc)
ElseIf e.CommandName = "InsertNew" Then
Dim refNo As TextBox = GridView2.FooterRow.FindControl("InsertRefNo")
Dim resource As TextBox = GridView2.FooterRow.FindControl("InsertResource")
Dim hours As TextBox = GridView2.FooterRow.FindControl("InsertHours")
Dim offset As TextBox = GridView2.FooterRow.FindControl("InsertOffset")
Dim newResAlloc As DataTable = resourceInfo.loadResAllocations
Dim newAllocRow As DataRow = newResAlloc.NewRow
newAllocRow.ItemArray = New Object() {Nothing, refNo.Text, resource.Text, hours.Text, offset.Text}
newResAlloc.Rows.Add(newAllocRow)
resourceInfo.updateResAllocations(newResAlloc)
End If
GridView2_DataBind() 'Culprit
End Sub
Right way:
Protected Sub GridView2_RowCommand(ByVal sender As Object, ByVal e As GridViewCommandEventArgs) Handles GridView2.RowCommand
If e.CommandName = "NewDataInsert" Then
Dim refNo As TextBox = GridView2.Controls(0).Controls(0).FindControl("NewRefNo")
Dim resource As TextBox = GridView2.Controls(0).Controls(0).FindControl("NewResource")
Dim hours As TextBox = GridView2.Controls(0).Controls(0).FindControl("NewHours")
Dim offset As TextBox = GridView2.Controls(0).Controls(0).FindControl("NewOffset")
Dim newResAlloc As DataTable = resourceInfo.loadResAllocations
Dim newAllocRow As DataRow = newResAlloc.NewRow
newAllocRow.ItemArray = New Object() {Nothing, refNo.Text, resource.Text, hours.Text, offset.Text}
newResAlloc.Rows.Add(newAllocRow)
resourceInfo.updateResAllocations(newResAlloc)
GridView2_DataBind() 'Only called if IF is true
ElseIf e.CommandName = "InsertNew" Then
Dim refNo As TextBox = GridView2.FooterRow.FindControl("InsertRefNo")
Dim resource As TextBox = GridView2.FooterRow.FindControl("InsertResource")
Dim hours As TextBox = GridView2.FooterRow.FindControl("InsertHours")
Dim offset As TextBox = GridView2.FooterRow.FindControl("InsertOffset")
Dim newResAlloc As DataTable = resourceInfo.loadResAllocations
Dim newAllocRow As DataRow = newResAlloc.NewRow
newAllocRow.ItemArray = New Object() {Nothing, refNo.Text, resource.Text, hours.Text, offset.Text}
newResAlloc.Rows.Add(newAllocRow)
resourceInfo.updateResAllocations(newResAlloc)
GridView2_DataBind() 'Only called if IF is true
End If
End Sub

request.querystring

how can i use request.querystring in asp.net.i have a linkbutton and this is in a repeater control.i want to play video for the corresponding link _click.i want to pass a fileID of the corresponding link to a function,how can i do this ?
<asp:Repeater ID="Repeater2" runat="server">
<ItemTemplate>
<asp:LinkButton runat="server" ID="LnkBtn"
OnClick="ButtonShowVideo_Click"><%#Eval("FileName")%>
</asp:LinkButton>
</ItemTemplate>
</asp:Repeater>
Protected Sub ButtonShowVideo_Click(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles ButtonShowVideo.Click
Repeater1.DataSource = GetSpecificVideo(**here i want to get the fileID**)
Repeater1.DataBind()
End Sub
Private Function GetSpecificVideo(ByVal i As Object) As DataTable
'pass the id of the video
Dim connectionString As String = ConfigurationManager
.ConnectionStrings("UploadConnectionString").ConnectionString
Dim adapter As New SqlDataAdapter("SELECT FileName, FileID,FilePath " +
"FROM FileM WHERE FileID = #FileID", connectionString)
adapter.SelectCommand.Parameters.Add("#FileID", SqlDbType.Int).Value =
DirectCast(i,Integer)
Dim table As New DataTable()
adapter.Fill(table)
Return table
End Function
This won't help you:
<asp:Repeater ID="Repeater2" runat="server">
<ItemTemplate>
<asp:LinkButton runat="server" ID="LnkBtn"
OnClick="ButtonShowVideo_Click"><%#Eval("FileName")%>
</asp:LinkButton>
</ItemTemplate>
</asp:Repeater>
as it will not put FileName into query stirng. Rather use this method:
<asp:Repeater ID="Repeater2" runat="server">
<ItemTemplate>
<asp:LinkButton runat="server" ID="LnkBtn"
CommandArgument='<%#Eval("FileName")%>'
OnClick="ButtonShowVideo_Click"><%#Eval("FileName")%>
</asp:LinkButton>
</ItemTemplate>
</asp:Repeater>
In code behind:
Protected Sub ButtonShowVideo_Click(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles ButtonShowVideo.Click
Dim btn as LinkButton = sender as LinkButton
if(btn is not null) then
if(NOT string.IsNullOrEmpty(btn.CommandArgument)) then
dim vid as integer = Convert.ToInt32(btn.CommandArgument)
Repeater1.DataSource = GetSpecificVideo(vid)
Repeater1.DataBind()
end if
end if
End Sub
If you plan to use query string, the button click can do either of the following:
Hyperlinks to a page with the designated quertstring to identify the action/entity etc
Do a server-side redirect to the page as describe in item 1 above
So where is your issue that you find challenging?

Editable gridview - what are the basics?

I'm trying to create a simple example of an editable gridview, and for some reason can't seem to get the basics working. Why is this example not displaying the label Bar and a textbox when I click on "edit"?
aspx:
<%# Page Language="vb" AutoEventWireup="false" CodeBehind="gv.aspx.vb" Inherits="WebRoot.gv" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<asp:GridView ID="gv" runat="server" AutoGenerateEditButton="true" AutoGenerateColumns="false">
<Columns>
<asp:TemplateField HeaderText="Foo">
<ItemTemplate>
<asp:Label ID="Label1" runat="server" Text="Foo" />
<asp:Label ID="lblQuarter" runat="server" Text='<%# Eval("fooVal") %>' />
</ItemTemplate>
<EditItemTemplate>
<asp:Label ID="lblQuarter" runat="server" Text='Bar' />
<asp:TextBox ID="TextBox1" runat="server" Text='<%# Eval("fooVal") %>'></asp:TextBox>
</EditItemTemplate>
</asp:TemplateField>
</Columns>
code behind:
Public Class MyFoo
Public ReadOnly Property FooVal() As String
Get
Return _val
End Get
End Property
Private _val As String = String.Empty
Public Sub New(ByVal val As String)
_val = val
End Sub
End Class
Partial Public Class gv
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim l As New List(Of MyFoo)
l.Add(New MyFoo("first"))
l.Add(New MyFoo("second"))
gv.DataSource = l
gv.DataBind()
End Sub
Private Sub gv_RowEditing(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewEditEventArgs) Handles gv.RowEditing
Dim x As String
x = "foo"
End Sub
End Class
Try hooking up OnRowEditing to your gv_RowEditing method. I'm surprised you don't get an error page, something like "fired event RowEditing which wasn't handled".
<asp:GridView ID="gv" OnRowEditing="gv_RowEditing" ...
Update
My bad. I assumed c# and keep forgetting to check the language. Put this in your rowediting method and the edit will work. But there's more to do in the cancel and update events.
gv.EditIndex = e.NewEditIndex
Dim l As New List(Of MyFoo)
l.Add(New MyFoo("first"))
l.Add(New MyFoo("second"))
gv.DataSource = l
gv.DataBind()
More details here: http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview.rowediting.aspx

Resources