As a customer's request, I'm migrating a Web Application that I've built in C# to Visual Basic and I'm having some trouble when trying to Databind a Datalist using a DataTable as Source.
In my original code, in C#, the DataList Databinding works great, but in Visual Basic throws a Null Reference Exception. I've done a step by step debugging and all the used variables are initialized and have data, so I'm wondering if there is a difference in the binding process between C# and Visual Basic.
Here is my original C# Code
public void CargarMiniaturas(Imagen iImagen) {
//I clear the DataList DataSource
dlMiniaturas.DataSource = null;
// Number of pages
int CantPaginas = iImagen.CantidadPaginas;
//Create DataTable and DataColumn
DataTable dt = new DataTable( );
DataColumn dc = new DataColumn("Imagen", typeof(System.String));
dt.Columns.Add(dc);
//Fill the data
for(int i = 0; i <= CantPaginas - 1; i++) {
DataRow dr = dt.NewRow( );
dr[0] = "data:image/gif;base64," + Globales.Imagen_a_Base64(iImagen.GetThumbnail(iImagen, i, new Size(120, 120)));
dt.Rows.Add(dr);
}
//Load the data into the DataList
dlMiniaturas.DataSource = dt;
dlMiniaturas.DataBind( );
dlMiniaturas.SelectedIndex = _iImagen.iNumPagina;
}
And my Visual Basic Code:
Public Sub CargarMiniaturas(iImagen As Imagen)
'I clear the DataList DataSource
dlMiniaturas.DataSource = Nothing
'Number of pages
Dim CantPaginas As Integer = iImagen.CantidadPaginas
'Create Datatable and Datacolumn
Dim dt As New DataTable()
Dim dc As New DataColumn("Imagen", GetType(System.String))
dt.Columns.Add(dc)
'Fill the data
For i As Integer = 0 To CantPaginas - 1
Dim dr As DataRow = dt.NewRow()
dr(0) = "data:image/gif;base64," + Globales.Imagen_a_Base64(iImagen.GetThumbnail(iImagen, i, New Size(120, 120)))
dt.Rows.Add(dr)
Next
'Load the data into the datalist
dlMiniaturas.DataSource = dt
dlMiniaturas.DataBind() ' Here is where throws the nullreference exception.
dlMiniaturas.SelectedIndex = _iImagen.iNumPagina
End Sub
In both cases, the parameter iImagen contains the custom Object that I'm using, with all it's properties and values. Also, all the variables used in this function have their corresponding values.
Basically, what I'm trying to do is to load a Multi Page Tiff image Thumbnails preview into a DataList, using some custom objects, which works perfectly on the C# project.
What I'm doing Wrong??
Some background:
My original solution includes several projects, in which I've isolated in a library all the code needed for the custom Image object (ImageViewer.Lib.dll) and other separate components to visualize the image in Windows Forms, WebForms and Windows Presentation Foundation.
To build the Visual Basic Project Web Visualization I've used references to the ImageViewer.Lib.dll that I've written in C#, so there's no need to rebuild anything but the web viewer.
I'm a Visual Basic newbie, so I've used an Online Code Converter. So far everything works great except this.
Any help or hint you can provide will be useful.
It was my mistake!!
I was using an ItemDataBound event, in which I had:
Protected Sub dlMiniaturas_ItemDataBound(sender As Object, e As DataListItemEventArgs)
If e.Item.ItemType = ListItemType.Item OrElse e.Item.ItemType = ListItemType.AlternatingItem OrElse e.Item.ItemType = ListItemType.SelectedItem Then
Dim dli As ImageButton = DirectCast(e.Item.FindControl("imbBtn"), ImageButton)
dli.Attributes.Add("ident", "btnMiniatura")
dli.Attributes.Add("index", e.Item.ItemIndex.ToString())
End If
End Sub
But in the aspx I had commented out the line with the control "imbBtn".
<asp:DataList ID="dlMiniaturas" CssClass="Tabla" runat="server" OnItemDataBound="dlMiniaturas_ItemDataBound" EnableViewState="False" CellPadding="4" ForeColor="#333333">
<ItemTemplate>
<%--<asp:ImageButton runat="server" ID="imbBtn" ImageUrl='<%# Eval("Imagen") %>' Width="100" Height="100" CommandArgument='<%# Container.ItemIndex %>' EnableViewState="false" BackColor="White" ImageAlign="Middle" />--%>
</ItemTemplate>
</asp:DataList>
So it was MY mistake.
Uncommenting the line solved the issue.
Anyway, thanks to everyone who spent time reading.
Related
I have an issue with the following code, the markup is as follows:
<asp:GridView ID="GridView" runat="server"
AutoGenerateEditButton="True"
OnRowDataBound="GridView_RowDataBound"
OnRowEditing="GridView_RowEditing"
OnRowUpdating="GridView_RowUpdating"
CssClass="gridv">
<Columns>
<asp:TemplateField HeaderText="ASN">
<ItemTemplate>
<asp:Label ID="lblASN" runat="server" Text='<% #Eval("ASN")%>'></asp:Label>
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox ID="txtASN" runat="server" Text='<%# Bind("ASN")%>' CssClass="form-control"></asp:TextBox>
</EditItemTemplate>
</asp:TemplateField>
...
However when I run this code to get the new changed values from the textboxes that were successfully generated and populated, I only get the initial values not the news that user has entered, the code behind this is:
Protected Sub GridView_RowUpdating(sender As Object, e As System.Web.UI.WebControls.GridViewUpdateEventArgs) Handles GridView.RowUpdating
Try
Dim row As GridViewRow = GridView.Rows(e.RowIndex)
Dim ID As Integer = DirectCast(row.FindControl("txtID"), TextBox).Text
Dim sASN As String = DirectCast(row.FindControl("txtASN"), TextBox).Text
Dim sDescription As String = DirectCast(row.FindControl("txtDescription"), TextBox).Text
Dim sManufacturer As String = DirectCast(row.FindControl("ddlmanufacturer"), DropDownList).SelectedValue
GridView.EditIndex = -1
Catch
End Try
ShowEmpDetails()
End Sub
So when I click the update button I use a message box to write the variables above and the values that I get are the same ones that got initially written to the textboxes, not the text that the user has changed?
I have worked out this code from a similar example in which this works with no issues, I honestly can not figure out what I am doing wrong?
As requested Page_Load event is calling this function:
Private Sub ShowEmpDetails()
Dim query As String = "SELECT * from inventory.all_items"
Dim cmd As MySqlCommand
cmd = New MySqlCommand(query)
cmd.Connection = myConn
Dim sda As New MySqlDataAdapter
sda.SelectCommand = cmd
Dim dt As New DataTable
sda.Fill(dt)
GridView.DataSource = dt
GridView.DataBind()
End Sub
Ok... there are so many things wrong with your coding approach that I don't know where to begin. Sorry.
Lets' start again and I'll explain how to properly pass values between the DOM and your code-behind.
Firstly, you need to understand how the DOM populates and builds the HTML for the browser to know what's going on.
I would test your project in Firefox and use the Inspector tool (right-click wep page). That tool is gold and has saved my already bald-head from revealing my skull!! :-)
As you know, the GridView control binds both the "view" and "edit" portions of the control into the same code. I can see you have Eval() for the view portion of the control (or the mode of the control I should say) and you have Bind() for the Edit mode. That is good. I personally hate BoundControls, as you cannot really see what's going on under the hood.
Next, avoid using AutoPostBack like the plaque! It's just ugly.
Get familiar with AjaxControlToolKit (there are others too, but start with the Ajax), and the ASP:UpdatePanel.
So in your case something like this ...
<asp:UpdatePanel ID="upADDMAIN" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:GridView ID="GridView" runat="server"
AutoGenerateEditButton="True"
OnRowDataBound="GridView_RowDataBound"
OnRowEditing="GridView_RowEditing"
OnRowUpdating="GridView_RowUpdating"
CssClass="gridv">
Try and put as much functionality back into the defaults of the GridView control. So go back to your DESIGNER mode in VStudio and add all the functionality you need like EDIT, UPDATE, DELETE, etc in the design mode of the GridView. This will also make sure your SQLDataSource is updated at the same time with the right SQL for the task.
Now why are you using OnRowEditing and OnRowUpdating?
My rule-of-thumb is always to keep things to a minimum and give as much control to ASP.net as possible. This avoids re-inventing the wheel with code-behind stuff that ASP.net can handle straight out of the box.
I generally use OnDataBound(), OnRowDataBound(), and OnRowUpdating() to both read the data and pre-UPDATE the data before the Update() gets called by the controls.
ie:
protected void gvLogins_RowDataBound(object sender, GridViewRowEventArgs e)
{
GridViewRow gvRow = (GridViewRow)e.Row;
{
if (gvRow.RowType == DataControlRowType.DataRow)
{
and
protected void gvLogins_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
//apply values to the SQL parameters for UPDATE, etc
GridViewRow gvRow = (GridViewRow)gvLogins.Rows[e.RowIndex];
to do some pre-Update updates outside of the GridView for example.
I never do prerendering or preloading of data in the PageLoad(). That is just re-inventing the wheel, when by default most ASP.net controls already have connectivity and updating built in!
Oh and to get the values of controls inside a GridView... just use FindControl() but in the right place! ie: the DataBound() events etc.
DropDownList ddlAgent = (DropDownList)gvRow.FindControl("ddlAgent");
HiddenField hfAgentID = (HiddenField)gvRow.FindControl("hfAgentID"); //from overall state,as EDIT mode defaults the hfAgentID to 0!
if (ddlAgent != null && hfAgentID != null)
ddlAgent.SelectedValue = hfAgentID.Value;
Sorry I only use C#, not VB.
Good luck.
I am currently busy creating a simple website. Files get copied on to my FTP server. On my web page is a Textbox,button and gridview.
Everything is working fine, when i load my website the gridview is not visible until you have search for something.At the moment i have no search code for my search button, i coded it to load every file into the grid view.
I now want to add some filtering when you click the search button, but i have no clue on how to do it and the Internet only shows how to do it with a database, but i am using New List object.
See my example code below. (This currently add all the files to the gridview)
Dim filePaths() As String = Directory.GetFiles(Server.MapPath("~/Uploads/IIC/"))
Dim dt As New DataTable
dt.Columns.Add("FileName", GetType(String))
dt.Columns.Add("FilePath", GetType(String))
dt.Rows.Clear()
For Each filePath As String In filePaths
dt.Rows.Add(Path.GetFileName(filePath), filePath)
Next
If GridView2.Columns.Count > 2 Then
For x = 2 To GridView2.Columns.Count - 1
GridView2.Columns.RemoveAt(2)
Next
End If
Dim FileNameCol As New BoundField
Dim FilePathCol As New BoundField
FileNameCol.DataField = "FileName"
FileNameCol.HeaderText = "FileName"
FilePathCol.DataField = "FilePath"
FilePathCol.DataField = "FilePath"
GridView2.Columns.Add(FileNameCol)
GridView2.Columns.Add(FilePathCol)
GridView2.DataSource = dt.Select("FileName LIKE '%" & TextBox1.Text & "%'")
GridView2.DataBind()
Any help showing me how to filter the gridview will help me a lot as i haven't really worked with lists before.
Note: The gridview does not use a Database
Designer Code for Gridview2
<asp:GridView ID="GridView2" runat="server" AutoGenerateColumns="false" PageSize="10" AllowPaging="true"
EmptyDataText = "No files uploaded" Width="251px">
<Columns>
<asp:BoundField DataField="Text" HeaderText="FileName" />
<asp:TemplateField>
<ItemTemplate>
<asp:LinkButton ID="lnkDownload" Text = "Download" CommandArgument = '<%# Eval("Value") %>' runat="server" OnClick = "DownloadFile"></asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
</Columns>
You can achieve that using a DataTable.
It has a .Select() function in which you can filter specific records inside the datatable (Like the WHERE part in a query but instead from a database, you are using it in a datatable)
Try this:
Dim filePaths() As String = Directory.GetFiles(Server.MapPath("~/Uploads/IIC/"))
Dim dt As New DataTable
dt.Columns.Add("FileName", GetType(String))
dt.Columns.Add("FilePath", GetType(String))
dt.Rows.Clear()
For Each filePath As String In filePaths
dt.Rows.Add(Path.GetFileName(filePath), filePath)
Next
If GridView2.Columns.Count > 1 Then
For x = 1 To GridView2.Columns.Count - 1
grdApproval.Columns.RemoveAt(1)
Next
End If
Dim FileNameCol As New BoundField
Dim FilePathCol As New BoundField
FileNameCol.DataField = "FileName"
FileNameCol.HeaderText = "FileName"
FilePathCol.DataField = "FilePath"
FilePathCol.HeaderText = "FilePath"
GridView2.Columns.Add(FileNameCol)
GridView2.Columns.Add(FilePathCol)
GridView2.DataSource = dt.Select("FileName LIKE '%" & txtYourSearchBox.Text & "%'")
GridView2.DataBind()
this may sound like a silly question but i am learning Visual Basic ASP.NET 4 and i have been asked to create a DropDownList which obtains information from a table using SQL. I cant seem to pull the selected item from the dropdownlist and show it on the screen using Request.Form.
I have tried this..
Dim selItem As String = Request.Form("DDList")
Response.Write(selItem)
but this does not show anything on screen. Please help as i am struggling with this.
I have added my dropdownlist as follows:
<asp:DropDownList ID="DDList" runat="server" Width="201px">
</asp:DropDownList>
<asp:DropDownList ID="DDList2" runat="server" Width="145px">
</asp:DropDownList>
My Class/Function
Public Class sqlFunc
Public Shared Function tableData() As DataSet
Dim oraConnect As New OracleConnection
oraConnect.ConnectionString = ConfigurationManager.ConnectionStrings("smart_dev").ConnectionString
Dim oraCommand As New OracleCommand
oraCommand.Connection = oraConnect
oraCommand.CommandType = Data.CommandType.Text
Dim lsSQL As String = ""
lsSQL = "SELECT code, description FROM ref_code WHERE domain = 'SPECIALTY'"
oraCommand.CommandText = lsSQL
Dim da As New OracleDataAdapter(oraCommand)
Dim ds As New DataSet
da.Fill(ds)
Return ds
End Function
What i am using on my .aspx.vb page;
Dim dsData1 As New DataSet
dsData1 = tableData()
DDList.DataSource = dsData1
DDList.DataValueField = "code"
DDList.DataTextField = "description"
DDList.DataBind()
DDList.Items.Insert(0, New ListItem(String.Empty, String.Empty))
DDList.SelectedIndex = 0
You don't need to get the selected value using Request.Form if you are using an asp:DropDown ASP.net control. All you have to do is:
Dim selItem As String = DDList.SelectedValue
Response.Write(selItem)
If you really want to use Request.Form, do it like this:
Dim selItem As String = Request.Form(DDList.ClientID)
Response.Write(selItem)
Also, make sure you have ViewState enabled and that you do not rebind the DropDown at PageLoad when there is a PostBack:
Sub Page_Load
If Not IsPostBack
' Bind your DropDown here
End If
End Sub
Until now, I was working with VS 2003 and recently migrated to VS 2008. I am facing some peculiar problems.
In Vs 2003,I had a Datagrid, and one of the field was ButtonField(Link button). It was not a template field. The user clicks on the field and some data gets generated.
I have written a code, in Vb, like this, on dg_ItemCommand:
Strid = Ctype(e.commandsource,linkbutton).text
Now i want to use same method,for the gridview (I think datagrid is gridview in 2008). I wrote a code like this on dg_Rowcomand
Private Sub dgSampleCustomer_RowCommand(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewCommandEventArgs) Handles dgSampleCustomer.RowCommand
Try
Dim strid As String
Dim i As Integer
strid = CType(e.CommandSource, LinkButton).Text
...
It is throwing a error.
Unable to cast object of type 'System.Web.UI.WebControls.GridView' to
type 'System.Web.UI.WebControls.ButtonField'.
Can anybody help me out!
It looks like the source of the command is the GridView itself, not the button you are clicking. What you probably want to do is set this value you are looking for in the "CommandArgument" property of the Linkbutton. The markup would look something like this:
<asp:LinkButton ID="myLinkButton" runat="server"
CommandName="MyCommandName"
CommandArgument="MySpecialValue"
Text="Click Me" />
Then in the event you would simply:
' strid = "MySpecialValue"
strid = e.CommandArgument.ToString()
Instead of pulling the ID from the name of the control, you can now easily get it from the command. CommandName is optional in this particular case, but comes in handy if you have multiple buttons on a grid that do different things, such as "Edit" and "Delete". Then you can use the command name to handle each command in their own way in the same event:
If (e.CommandName = "Edit") Then
' Do Some Edit Code
End If
I'm wondering why you are trying to cast the command source to a LinkButton? If you would like to attach or otherwise send some kind of row-specific information to your button handler, you are able to do this with the CommandName and CommandArgument attributes of the ButtonField.
Like:
<asp:Gridview ID="...">
...
<columns>
<asp:buttonfield buttontype="Link"
commandname="Generate"
text="Generate"/>
...
</columns>
</asp:GridView>
This will be retrievable in the event handler by using:
if(e.CommandName=="Generate")
{
// Convert the row index stored in the CommandArgument
// property to an Integer.
string rowIndex = Convert.ToInt32(e.CommandArgument);
...
}
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview.rowcommand.aspx
UPDATE: (use DataKeys)
Since e.CommandArgument returns a row index, and you want the ID, use the DataKeys collection, first add your ID column to the DataKeyNames collection...
<asp:GridView ... DataKeyNames="ID">
... and then retrieve the values from the DataKeys collection, like:
GridView sourceGridView = (GridView) e.CommandSource;
rowIndex = Convert.ToInt32(e.CommandArgument);
strID = sourceGridView.DataKeys[rowIndex]["ID"];
You can try this in your rowcommand event
Dim index = Convert.ToInt32(e.CommandArgument)
Dim row = dg.Rows(index)
'find your linkbutton in template field (replace "lnkBtn" with your's)
Dim myLinkButton = CType(row.FindControl("lnkBtn"), LinkButton)
Dim strid As String = myLinkButton.Text
Let me know if it helps.
On my ASP.NET content page, I have a DropDownList and a DataGrid. The DropDownList is populated from the results of an SQL query when the page loads. I want the DataGrid to be populated from the results of an SQL Query, but that query depends on the selected item of the DropDownList. I have an event handler for DropDownList1.SelectedIndexChanged, which calls a function PopulateDG. This function gets the selected item from the DropDown (defaulting to the first element if SelectedItem is Nothing), creates an SQLDataAdapter, queries the database, fills the DataSet, and finally calls the DataGrid's DataBind(). This all works perfectly when the function is called from the DropDown's event handler.
I would now like to have the DataGrid appear when the page is first loaded, using the information from the first element of the DropDown (since it'd be before the user has selected anything). I have tried putting PopulateDG in the Init, PreInit, PreRender, Load, and Unload handlers for the Page and both controls, to no avail. When I use the debugger, I can see that the ItemsGrid.DataSource does indeed have the information I want, but ItemsGrid.DataBind does not seem to cause the Data Grid to appear on the page like it does when called from the SelectedIndexChanged handler. The control simply doesn't render onto the page.
PopulateDG:
Protected Sub PopulateDG()
Dim WeekId As Integer
Dim DDIdx As Integer
If DropDownList1.SelectedItem Is Nothing Then
DDIdx = 0
Else
DDIdx = DropDownList1.SelectedIndex
End If
WeekId = DropDownList1.Items.Item(DDIdx).Value
Dim myConnection As SqlConnection
Dim SQLCommand As SqlDataAdapter
Dim rootWebConfig As System.Configuration.Configuration
rootWebConfig = Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~/Web.config")
Dim connString As System.Configuration.ConnectionStringSettings
connString = rootWebConfig.ConnectionStrings.ConnectionStrings("ConnectionString")
If Not (connString.ConnectionString = Nothing) Then
Console.WriteLine("Northwind connection string = " & connString.ConnectionString)
Else
Console.WriteLine("No Northwind connection string")
End If
myConnection = New SqlConnection(connString.ConnectionString)
SQLCommand = New SqlDataAdapter("SELECT CONVERT(VARCHAR(10), WorkDate, 101) AS WorkDate, CONVERT(VARCHAR(10), WorkStartTime, 8) AS StartTime, CONVERT(VARCHAR(10), WorkEndTime, 8) AS EndTime, BreakMinutes FROM Days WHERE WeekId = " & WeekId & " ORDER BY WorkDate", myConnection)
Dim ds As DataSet = New DataSet()
SQLCommand.Fill(ds)
ItemsGrid.DataSource = ds
ItemsGrid.DataBind() 'DEBUGGER BREAK POINT HERE
End Sub
Content markup of my aspx page:
<asp:Content ID="Content3" ContentPlaceHolderID="MainContent" Runat="Server">
<asp:DropDownList ID="DropDownList1"
runat="server"
DataSourceID="TimeSheetDB"
DataTextField="WeekEndLabel"
DataValueField="WeekId"
OnSelectedIndexChanged="DropDownList1_SelectedIndexChanged"
AutoPostBack="True">
</asp:DropDownList>
<asp:SqlDataSource ID="TimeSheetDB"
runat="server"
ConnectionString="<%$ ConnectionStrings:ConnectionString %>"
SelectCommand="SELECT [WeekId], 'Week Ending ' + CONVERT(varchar(10), EndDate, 101) AS WeekEndLabel FROM [Weeks] ORDER BY [EndDate]">
</asp:SqlDataSource>
<asp:DataGrid id="ItemsGrid"
BorderColor="black"
BorderWidth="1"
CellPadding="3"
AutoGenerateColumns="true"
runat="server"
>
</asp:DataGrid>
</asp:Content>
At the second to last line of the sub, I have a break point, and using the debugger I can see that ItemsGrid.DataSource.Tables.List(0) is populated exactly as I'd like, but the DataBind function seems to do nothing when called from anywhere except the SelectedItemChanged event handler. How can I make it work correctly when the page first loads?
I figured out the problem. The call to PopulateDG has to come in the DropDown's PreRender event handler. My problem seems to have been that I was trying to use the function either too early (ie, before the items were loaded into the DropDown control) or too late (after ASP had already determined how the DataGrid should appear, I assume, so that calling DataBind at that point had no effect). Clearly, I need to read up more on the various execution phases of pages and controls.