Convert a gridview templatefield to pdf iTextSharp - asp.net

I have a GridView which is programatically filled from the DB (not a SqlDataSource or such). There are 4 columns which are TemplateFields as I format their text. They are Dates and Times and this is the one of their TemplateField:
<ItemTemplate>
<asp:Label ID="Label1" Text='<%# FormatDate(Eval("tDate")) %>' runat="server"></asp:Label>
</ItemTemplate>
This is the function to format that date:
Function FormatDate(objTime As Object) As String
Dim d As String
If objTime.Equals(DBNull.Value) Then
d = ""
Else
d = Convert.ToDateTime(objTime).ToString("MM-dd-yyyy")
End If
Return d
End Function
I've been using the method in this Post which was converted to VB code from this to convert the GridView to a PDF using iTextSharp.
My issue is that I'm getting a Null Reference exception here when adding the GridView data to the PDF(inside the For Loops):
Dim lc As DataBoundLiteralControl = TryCast(gvReport.Rows(rowNo).Cells(colNo).Controls(0), DataBoundLiteralControl)
s = lc.Text.Trim()
And if I remove this If statement and just run the Else part here:
s = gvReport.Rows(rowNo).Cells(colNo).Text.Trim()
ph = New Phrase(s, FontFactory.GetFont("Arial", ReportTextSize, iTextSharp.text.Font.NORMAL))
mainTable.AddCell(ph)
These Date/Time columns show up as empty on the PDF while all other columns show up with no issues.
I'm very lost on how to resolve this issue and have been unsuccessful in finding a solution online.

While I wasn't able to fix the solution I was following up above, I found a different way to access data from a TemplateField:
Dim s As String = CType(gvReport.Rows(rowNo).FindControl("Label1"), Label).Text
This gives me access to the data in the specified column. Now I just need to figure out a way iterate through the row and get each of the different TemplateFields which will probably involve reworking my For loops and a Select Case statement.

You are getting Nothing because TryCast will store Nothing if it cannot cast the value.
In bound columns, the control is 0, but in an edit item template like that, it is 1.
So you have to change
Dim lc As DataBoundLiteralControl = TryCast(gvReport.Rows(rowNo).Cells(colNo).Controls(0), DataBoundLiteralControl)
to
Dim lc As Label = TryCast(gvReport.Rows(rowNo).Cells(colNo).Controls(1), Label)

Related

Format BoundField Data Types Dynamically

I'm using a CheckBoxList to define which columns are displayed in a GridView. I populate the CheckBoxList using a query like
select column_name, data_type from information_schema.columns
where table_name = 'myTable'
After the user has chosen the columns (with various Data Types in them) they wish to display, they press a button and the following snippet of VB code generates the GridView.
For Each item As ListItem In chooseColsList.Items
If item.Selected Then
Dim bf As New BoundField()
'PRODUCES BUGGY RESULTS BECAUSE APPLIED TO ALL BoundFields
bf.DataFormatString = "{0:dd-MMM-yyyy}"
bf.ApplyFormatInEditMode = True
bf.DataField = item.Value
bf.HeaderText = item.Value
bf.SortExpression = item.Value
statusReportGrid.Columns.Add(bf)
End If
Next
What I want to do is to apply the DataFormatString ONLY to the columns with a 'date' Data Type in them. However, I have found no way of programmatically determining the Type of the data in the column being bound, no any way of passing this info to the Control. This information exists in the information_schema, as shown in my query, but I don't know how to extract that out and use it to dynamically setup my BoundFields. It is important to note that I'm using an SqlDataSource.
I've experimented with just about every possible solution I can think of and end up here.
Thanks in advance for your help, it is VERY appreciated :)
If you set your check box list like this:
<asp:checkboxlist id="list" runat="server"
DataTextField="column_name" DataValueField="data_type" DataSourceID="YourDSID" />
You should be able to iterate through the items and check the value of the current Item like so:
For Each item As ListItem In chooseColsList.Items
If item.Selected Then
Dim bf As New BoundField()
If StrComp(item.Value,"date") = 0 Then 'Or however datetime is returned
bf.DataFormatString = "{0:dd-MMM-yyyy}"
bf.ApplyFormatInEditMode = True
End If
bf.DataField = item.Text
bf.HeaderText = item.Text
bf.SortExpression = item.Text
statusReportGrid.Columns.Add(bf)
End If
Next

Is it possible to have a DataColumn with a space in the name and how can I do it?

I have a DataTable that I am creating and binding to a GridView. Currently the headers do not have any spaces and it makes it hard to read. I want to space them out but I'm having a minor issue.
What I am trying to accomplish :
Dim dc As Data.DataColumn
dc = New Data.DataColumn("Updated Date", System.Type.GetType("System.String"))
dt.Columns.Add(dc)
What I currently have :
Dim dc As Data.DataColumn
dc = New Data.DataColumn("UpdatedDate", System.Type.GetType("System.String"))
dt.Columns.Add(dc)
I know that I can set the HeaderText in the columns declaration like below, but I won't know how any columns I am going to have. And would rather the columns be generated automatically.
<Columns>
<asp:BoundField DataField="UpdatedDate" HeaderText="Updated Date" />
</Columns>
You might not want to use the constructor, and instantiate a column. This way you can set a property like below:
Dim col As New GridViewColumn()
col.DisplayMemberBinding = New Binding("UpdatedDate")
col.Header = "Updated Date"
dt.Columns.Add(col)
Hope this is what you are looking for
I believe names should not contain spaces, unless you want to create yourself bigger problems later. You can generate the column titles automatically by writing a line of code that inserts a space every time there is a capital letter in the name.

problem binding to filtered dataview

I'm having a problem with the dtaview. I'm dynamically creating new datacolumns, assigning them values, and adding them into my datatable. Before using a filter, this was fine when binding. All values appeared.
However, I have since chosen to reduce returned results by filtering (by letter), and my returned dataview doesn't seem to allow binding with the newly created data columns. I've mined into the filtered view, and can see that the values are present that I need.
I'm trying to avoid putting everything back into a table again after applying the filter. An sql query based on letter is out of the question, as the whole original table is sitting in view state.
Here are some code snippets:
--Firstly create new datacolumn
Dim ICount As System.Data.DataColumn = New System.Data.DataColumn
ICount.DataType = System.Type.GetType("System.String")
ICount.AllowDBNull = True
ICount.ColumnName = "ICount"
register.Columns.Add(ICount)
--integer value is first calculated and then put into the datatable row
row("ICount") = IntegerCount.ToString()
--filtered view is created from datatable (returned from viewstate)
Dim filteredView As New Data.DataView(pTable, FilterExpression, "Surname", Data.DataViewRowState.OriginalRows)
--view is bound
grd.DataSource = filteredView
grd.DataBind()
--Markup
<asp:TemplateField HeaderText ="ICount" SortExpression="ICount">
<ItemTemplate>
<asp:Label ID="IC" runat="server" Text='<%# Bind("ICount") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
All of the non dynamic datacolumns are fine. Mining into both the datatable and the filtered view show values are there.
Any help would be much appreciated!!!
Ok - fixed this.
The problem was that I wasn't using the dataset.
So instead of creating a new view, I should have done the following:
datTable = CType(ViewState("datTable"), System.Data.DataTable)
datSet.Tables.Add(datTable)
datView = datSet.Tables(0).DefaultView
datView.RowFilter = FilterExpression
grd.DataSource = datView
grd.DataBind()
All values are now coming through.

Adding Column Value Dynamically to a DataGridview

I have three column in my datagridview .One is text ,one is Combo and another one is Text ...i don't want to use datasource want to add values on cell like datagridview.Rows[].cells[].value. Help me how i can do it? My database have several columns...How to add column value dynamically....
I just had to do the same exact type of thing...here is how you add a column.
If Not IsPostBack Then <br>
Dim field As New TemplateField
field.HeaderText = "Name of Column"
Dim col As DataControlField = field
GridView.Columns.Add(col)
End If
**In the Gridview_rowcreated Sub
e.row.cells(cellnumber from 0 to N).controls.Add(data)
you're going to have to create a connection and a connection string
here is an example...
Dim Dbconn As SqlConnection
Dim Dbcmd As SqlCommand
Dbcmd = New Data.SqlClient.SqlCommand()
Dbcmd.Connection = Dbconn
Dbcmd.CommandType = Data.CommandType.Text
Dbcmd.Commandtext = "select * from table"
dbconn.open()
//then you need a data reader
dim dr as sqlclient.sqldatareader
dr = dbcmd.executereader
while dr.read
add each item to a list
end while
then on page load set your datasource of the grid to the list
hope this helps...if you have any questions just ask me.
I would highly recommend to use a Repeater instead of datagridview and render as many columns as you want.
.aspx code
<tr>
<asp:Repeater ID="rptDayHeaders" runat="server">
<ItemTemplate>
<td>
<strong><asp:Literal ID="ltMonthHeader" runat="server"></asp:Literal></strong>
</td>
</ItemTemplate>
</asp:Repeater>
</tr>
.aspx.vb code
rptDayHeaders.DataSource = daysList
rptDayHeaders.DataBind()
where dayslist needs to be an array of the number of columns you want.
We have used the same approach to generate a complete Gantt Chart
Try something along the lines of
dataGrid.Rows.Add(new object[] { "value1", 42, "value3"});

How to list some specific images in some folder on web server?

Let me explain:
this is path to this folder: > www.my_site.com/images
And images are created by user_id, and for example, images of user_id = 27 are,
27_1.jpg, 27_2.jpg, 27_3.jpg!
How to list and print images which start with 27_%.jpg?
I hope You have understood me!
PS. I am totally beginmer in ASP.NET (VB) and please give me detailed information
Here starts my loop
while dbread.Read()
'and then id user_id
dbread('user_id')
NEXT???
I nedd to create XML, till now I created like this:
act.WriteLine("")
act.WriteLine("http://www.my_site.com/images/"&dbread("user_id")&"_1.jpg")
act.WriteLine("")
But this is not answer because I need to create this nodes how many images of this user exist?
In database doesn't exist list of this images so that is reason why I must count them in folder. (this is not my site exacly, but I need to create XMl on this site)
Do you understand me?
The best way is to just loop through all the files in the directory.
While dbRead.Read
dim sUserId as String= dbread('user_id')
For Each sFile As String In IO.Directory.GetFiles("C:\")
if sFile.StartsWith (sUserId) Then
'Do something.
End If
Next
Loop
However, to actually show the images, you're best bet could be to create a datatable of these images, and then use a datalist or repeater control to display them.
Dim dtImages as new DataTable
dtImages.Columns.Add("Filename")
If dbRead.Read
dim sUserId as String= dbread('user_id')
For Each sFile As String In IO.Directory.GetFiles("C:\")
if sFile.StartsWith (sUserId) Then
Dim drImage as DataRow = dtImages.NewRow
drImage("Filename") = sFile
dtImages.Rows.add(drImage)
End If
Next
End If
dlImages.DataSource = dtImages
dlImages.DataBind
Then, on your ASPX page, you would have a datalist control called dlImages defined like:
<asp:datalist id="dlImages" RepeatDirection="Horizontal" runat="server" RepeatLayout="Flow" Height="100%">
<ItemTemplate>
<asp:Image ID="Image1" Runat=server ImageUrl='<%# Server.MapPath("photos") & Container.DataItem("FileName") %>'>
</asp:Image>
</ItemTemplate>
</asp:datalist>
The appropriate method would be to do the following
Get the listing of files using System.IO.Directory.GetFiles("YourPath", UserId + "_*.jpg")
Loop through this listing and build your XML or then render it out to the user.
Basically the GetFiles method accepts a path, and a "filter" parameter which allows you to do a wildcard search!
EDIT:
The GetFiles operation returns a listing of strings that represent the full file name, you can then manipulate those values using the System.IO.Path.GetFileName() method to get the actual file name.
You can use the XmlDocument class if you want to actually build the document, or you could do it with a simple loop and a string builder. Something like the following.
StringBuilder oBuilder = new StringBuilder();
oBuilder.Append("<root>");
string[] ofiles = Directory.GetFiles("YourPath", "yourMask");
foreach(string currentString in oFiles)
{
oBuilder.AppendLine("<file>http://yourpath/" + Path.GetFileName(currentString) + "</file>");
}
oBuilder.Append("</root");

Resources