How to export grid data as excel in LightSwitch Web Application
Someone recently asked me how to export LightSwitch grid to excel format. Well sounds easy in Desktop Mode coz there is inbuilt option when you publish application in Desktop mode but what about when application is published as web app?
I am going to show two different techniques First one is export as true Excel file and second technique is export as csv format but save as *.xls so it can open comma separated file in excel…
– To use below code create a button on your search screen and name it ExportCSV (or something else but I am using that name in this example)
– Right click on your button and click Edit Execute code and it will open code window.
– In my case screen name was SearchOrdersSearchQuery so place some initialize code such as Adding Event Handler
– Couple of things to notice in below code. First we register some event handlers, second we use
stream As New StreamWriter(dialog.OpenFile()) rather than using file paths because in web mode you don’t have access to host machine file system direct way for security reason so LightSwitch Provides you access to Stream where you can write data.
Technique-1: Export as CSV – comma separated file and Save as Excel
Imports System.Text Namespace LightSwitchApplication Public Class SearchOrdersSearchQuery Private Sub SearchOrdersSearchQuery_Created() Dim CSVButton = Me.FindControl("ExportCSV") AddHandler CSVButton.ControlAvailable, AddressOf ExportCSV_ControlAvailable End Sub Private Sub ExportCSV_ControlAvailable(sender As Object, e As ControlAvailableEventArgs) RemoveHandler Me.FindControl("ExportCSV").ControlAvailable, AddressOf ExportCSV_ControlAvailable Dim Button = DirectCast(e.Control, Button) AddHandler Button.Click, AddressOf ExportCSV_Click End Sub Private Sub ExportCSV_Click(sender As Object, e As System.Windows.RoutedEventArgs) Dim collectionProperty As Microsoft.LightSwitch.Details.Client.IScreenCollectionProperty = Me.Details.Properties.OrdersSearchQuery Dim intPageSize = collectionProperty.PageSize 'Get the Current PageSize and store to variable collectionProperty.PageSize = 0 Dim dialog = New SaveFileDialog() dialog.Filter = "Excel (*.xls)|*.xls" If dialog.ShowDialog() = True Then Using stream As New StreamWriter(dialog.OpenFile()) Dim csv As String = GetCSV() stream.Write(csv) stream.Close() Me.ShowMessageBox("Excel File Created Successfully. " & vbCrLf & "NOTE: When you open excel file and if you receive prompt about invalid format then just click yes to continue.", "Excel Export", MessageBoxOption.Ok) End Using End If collectionProperty.PageSize = intPageSize 'Reset the Current PageSize End Sub '//Selected columns 'Private Function GetCSV() As String ' Dim csv As New StringBuilder() ' csv.AppendFormat("Heading1 , Heading2, Heading3" & "," & System.Environment.NewLine) ' For Each c In Me.EvacuationRegistrations ' csv.AppendFormat(Convert.ToString(c.first_name) & "," & Convert.ToString(c.last_name) & "," & Convert.ToString(c.location) & "," & System.Environment.NewLine, c) ' Next ' Return csv.ToString(0, (csv.Length - 1)) 'End Function Private Function GetCSV() As String Dim csv As New StringBuilder() Dim i As Integer = 0 For Each orderRow In OrdersSearchQuery '//HEADER If i = 0 Then Dim c As Integer = 0 For Each prop In orderRow.Details.Properties.All().OfType(Of Microsoft.LightSwitch.Details.IEntityStorageProperty)() If c > 0 Then csv.Append(vbTab) End If c = c + 1 csv.Append(prop.DisplayName) Next End If csv.AppendLine("") '//DATA ROWS Dim c1 As Integer = 0 For Each prop In orderRow.Details.Properties.All().OfType(Of Microsoft.LightSwitch.Details.IEntityStorageProperty)() If c1 > 0 Then csv.Append(vbTab) End If c1 = c1 + 1 csv.Append(prop.Value) Next i = i + 1 Next If csv.Length > 0 Then Return csv.ToString(0, csv.Length - 1) Else Return "" End If End Function '//Selected columns Private Function GetCSV_old() As String Dim csv As New StringBuilder() Dim i As Integer = 0 For Each a In OrdersSearchQuery If i = 0 Then csv.AppendFormat("OrderId" & "," & "OrderDate" & System.Environment.NewLine, a) End If csv.AppendFormat(a.OrderID & "," & a.OrderDate & System.Environment.NewLine, a) i = i + 1 Next If csv.Length > 0 Then Return csv.ToString(0, csv.Length - 1) Else Return "" End If End Function End Class End Namespace
Once you run LightSwitch application you can click on button “ExportToCVS” and it will generate tab separated file which can be opened in Excel.
Below post was very useful where I got this trick.
How to export data to CSV using Microsoft Lightswitch Web Application.
Technique-2: Export as true Excel file (Use ExcelWriter Class)
Here is full code which shows how to export data as true excel file (Binary format) which cant be viewed in text editor.
Imports System.Text Namespace LightSwitchApplication Public Class SearchOrdersSearchQuery Private Sub SearchOrdersSearchQuery_Created() Dim CSVButton = Me.FindControl("ExportToExcel") AddHandler CSVButton.ControlAvailable, AddressOf ExportCSV_ControlAvailable End Sub Private Sub SearchClick_Execute() OrdersSearchQuery.Refresh() End Sub Private Sub ExportCSV_ControlAvailable(sender As Object, e As ControlAvailableEventArgs) RemoveHandler Me.FindControl("ExportToExcel").ControlAvailable, AddressOf ExportCSV_ControlAvailable Dim Button = DirectCast(e.Control, Button) AddHandler Button.Click, AddressOf ExportCSV_Click End Sub Dim EXPORT_FORMAT As String = "EXCEL" '// or CSV Private Sub ExportCSV_Click(sender As Object, e As System.Windows.RoutedEventArgs) If EXPORT_FORMAT = "CSV" Then ExportAsCSV() Else ExportAsExcel() End If End Sub Sub ExportAsExcel() Dim collectionProperty As Microsoft.LightSwitch.Details.Client.IScreenCollectionProperty = Me.Details.Properties.OrdersSearchQuery Dim intPageSize = collectionProperty.PageSize 'Get the Current PageSize and store to variable collectionProperty.PageSize = 0 'Dim stream As New FileStream("demo.xls", FileMode.OpenOrCreate) 'Dim writer As New ExcelWriter(stream) 'writer.BeginWrite() 'writer.WriteCell(0, 0, "ExcelWriter Demo") 'writer.WriteCell(1, 0, "int") 'writer.WriteCell(2, 0, "double") 'writer.WriteCell(1, 1, 10) 'writer.WriteCell(2, 1, 1.5) 'writer.WriteCell(3, 0, "empty") 'writer.WriteCell(3, 1) 'writer.EndWrite() 'stream.Close() Dim dialog = New SaveFileDialog() dialog.Filter = "Excel (*.xls)|*.xls" If dialog.ShowDialog() = True Then Using fileStream As Stream = dialog.OpenFile() Using writer1 As New ExcelWriter(fileStream) Dim csv As String = GetCSV() writer1.BeginWrite() Dim rowsWritten As Integer = WriteToExcel(writer1) writer1.EndWrite() Me.ShowMessageBox("Excel File Created Successfully. Total " & rowsWritten & " written.", "Excel Export", MessageBoxOption.Ok) End Using End Using End If collectionProperty.PageSize = intPageSize 'Reset the Current PageSize End Sub Sub ExportAsCSV() Dim collectionProperty As Microsoft.LightSwitch.Details.Client.IScreenCollectionProperty = Me.Details.Properties.OrdersSearchQuery Dim intPageSize = collectionProperty.PageSize 'Get the Current PageSize and store to variable collectionProperty.PageSize = 0 Dim dialog = New SaveFileDialog() dialog.Filter = "Text Files (*.csv)|*.csv" If dialog.ShowDialog() = True Then Using stream As New StreamWriter(dialog.OpenFile()) Dim csv As String = GetCSV() stream.Write(csv) stream.Close() Me.ShowMessageBox("CSV File Created Successfully. " & vbCrLf & "NOTE: When you open excel file and if you receive prompt about invalid format then just click yes to continue.", "Excel Export", MessageBoxOption.Ok) End Using End If collectionProperty.PageSize = intPageSize 'Reset the Current PageSize End Sub '//Selected columns 'Private Function GetCSV() As String ' Dim csv As New StringBuilder() ' csv.AppendFormat("Heading1 , Heading2, Heading3" & "," & System.Environment.NewLine) ' For Each c In Me.EvacuationRegistrations ' csv.AppendFormat(Convert.ToString(c.first_name) & "," & Convert.ToString(c.last_name) & "," & Convert.ToString(c.location) & "," & System.Environment.NewLine, c) ' Next ' Return csv.ToString(0, (csv.Length - 1)) 'End Function Private Function GetCSV() As String Dim csv As New StringBuilder() Dim i As Integer = 0 For Each orderRow In OrdersSearchQuery '//HEADER If i = 0 Then Dim c As Integer = 0 For Each prop In orderRow.Details.Properties.All().OfType(Of Microsoft.LightSwitch.Details.IEntityStorageProperty)() If c > 0 Then csv.Append(vbTab) End If c = c + 1 csv.Append(prop.DisplayName) Next End If csv.AppendLine("") '//DATA ROWS Dim c1 As Integer = 0 For Each prop In orderRow.Details.Properties.All().OfType(Of Microsoft.LightSwitch.Details.IEntityStorageProperty)() If c1 > 0 Then csv.Append(vbTab) End If c1 = c1 + 1 csv.Append(prop.Value) Next i = i + 1 Next If csv.Length > 0 Then Return csv.ToString(0, csv.Length - 1) Else Return "" End If End Function '//Selected columns Private Function GetCSV_old() As String Dim csv As New StringBuilder() Dim i As Integer = 0 For Each a In OrdersSearchQuery If i = 0 Then csv.AppendFormat("OrderId" & "," & "OrderDate" & System.Environment.NewLine, a) End If csv.AppendFormat(a.OrderID & "," & a.OrderDate & System.Environment.NewLine, a) i = i + 1 Next If csv.Length > 0 Then Return csv.ToString(0, csv.Length - 1) Else Return "" End If End Function Private Function WriteToExcel(writer As ExcelWriter) As Integer 'writer.WriteCell(0, 0, "ExcelWriter Demo") 'writer.WriteCell(1, 0, "int") 'writer.WriteCell(1, 1, 10) 'writer.WriteCell(2, 0, "double") 'writer.WriteCell(2, 1, 1.5) 'writer.WriteCell(3, 0, "empty") 'writer.WriteCell(3, 1) Dim rowNum As Integer = 0 For Each orderRow In OrdersSearchQuery '//HEADER If rowNum = 0 Then WriteExcelHeaderRow(orderRow, writer) End If '//DATA ROWS WriteExcelDataRow(rowNum, orderRow, writer) rowNum = rowNum + 1 Next Return rowNum End Function Private Sub WriteExcelHeaderRow(orderRow As Order, writer As ExcelWriter) Dim colNum1 As Integer = 0 For Each prop In orderRow.Details.Properties.All().OfType(Of Microsoft.LightSwitch.Details.IEntityStorageProperty)() writer.WriteCell(0, colNum1, prop.DisplayName) colNum1 = colNum1 + 1 Next End Sub Private Sub WriteExcelDataRow(rowNum As Integer, orderRow As Order, writer As ExcelWriter) Dim colNum2 As Integer = 0 For Each prop In orderRow.Details.Properties.All().OfType(Of Microsoft.LightSwitch.Details.IEntityStorageProperty)() Select Case prop.PropertyType.Name Case "Int32", "Int64" writer.WriteCell(rowNum, colNum2, Convert.ToInt64(prop.Value)) Case "Double", "Decimal" writer.WriteCell(rowNum, colNum2, Convert.ToDouble(prop.Value)) Case Else writer.WriteCell(rowNum, colNum2, Convert.ToString(prop.Value)) End Select colNum2 = colNum2 + 1 Next End Sub End Class ''' <summary> ''' Produces Excel file without using Excel ''' </summary> Public Class ExcelWriter Implements IDisposable Private flagStarted As Boolean Private stream As Stream Private writer As BinaryWriter Private clBegin As UShort() = {&H809, 8, 0, &H10, 0, 0} Private clEnd As UShort() = {&HA, 0} ''' <summary> ''' Initializes a new instance of the <see cref="ExcelWriter"/> class. ''' </summary> ''' <param name="stream">The stream.</param> Public Sub New(stream As Stream) Me.stream = stream writer = New BinaryWriter(stream) End Sub Private Sub WriteUshortArray(value As UShort()) For i As Integer = 0 To value.Length - 1 writer.Write(value(i)) Next End Sub ''' <summary> ''' Writes the text cell value. ''' </summary> ''' <param name="row">The row.</param> ''' <param name="col">The col.</param> ''' <param name="value">The string value.</param> Public Sub WriteCell(row As Integer, col As Integer, value As String) Dim clData As UShort() = {&H204, 0, 0, 0, 0, 0} Dim iLen As Integer = value.Length Dim plainText As Byte() = StringToAscii(value) '//Encoding.ASCII.GetBytes(value) //Becuase SilverLight doesnt have ASCII Encoding I wrote little function clData(1) = CUShort(8 + iLen) clData(2) = CUShort(row) clData(3) = CUShort(col) clData(5) = CUShort(iLen) WriteUshortArray(clData) writer.Write(plainText) End Sub Private Function StringToAscii(s As String) As Byte() Dim retval As Byte() = New Byte(s.Length - 1) {} For ix As Integer = 0 To s.Length - 1 Dim ch As Char = s(ix) If AscW(ch) <= &H7F Then retval(ix) = CByte(AscW(ch)) Else retval(ix) = CByte(AscW("?"c)) End If Next Return retval End Function ''' <summary> ''' Writes the integer cell value. ''' </summary> ''' <param name="row">The row number.</param> ''' <param name="col">The column number.</param> ''' <param name="value">The value.</param> Public Sub WriteCell(row As Integer, col As Integer, value As Integer) Dim clData As UShort() = {&H27E, 10, 0, 0, 0} clData(2) = CUShort(row) clData(3) = CUShort(col) WriteUshortArray(clData) Dim iValue As Integer = (value << 2) Or 2 writer.Write(iValue) End Sub ''' <summary> ''' Writes the double cell value. ''' </summary> ''' <param name="row">The row number.</param> ''' <param name="col">The column number.</param> ''' <param name="value">The value.</param> Public Sub WriteCell(row As Integer, col As Integer, value As Double) Dim clData As UShort() = {&H203, 14, 0, 0, 0} clData(2) = CUShort(row) clData(3) = CUShort(col) WriteUshortArray(clData) writer.Write(value) End Sub ''' <summary> ''' Writes the empty cell. ''' </summary> ''' <param name="row">The row number.</param> ''' <param name="col">The column number.</param> Public Sub WriteCell(row As Integer, col As Integer) Dim clData As UShort() = {&H201, 6, 0, 0, &H17} clData(2) = CUShort(row) clData(3) = CUShort(col) WriteUshortArray(clData) End Sub ''' <summary> ''' Must be called once for creating XLS file header ''' </summary> Public Sub BeginWrite() flagStarted = True WriteUshortArray(clBegin) End Sub ''' <summary> ''' Ends the writing operation, but do not close the stream ''' </summary> Public Sub EndWrite() WriteUshortArray(clEnd) writer.Flush() flagStarted = False End Sub #Region "IDisposable Support" Private disposedValue As Boolean ' To detect redundant calls ' IDisposable Protected Overridable Sub Dispose(disposing As Boolean) If Not Me.disposedValue Then If disposing Then ' TODO: dispose managed state (managed objects). End If If writer IsNot Nothing Then writer.Dispose() End If ' TODO: free unmanaged resources (unmanaged objects) and override Finalize() below. ' TODO: set large fields to null. End If Me.disposedValue = True End Sub ' TODO: override Finalize() only if Dispose(ByVal disposing As Boolean) above has code to free unmanaged resources. 'Protected Overrides Sub Finalize() ' ' Do not change this code. Put cleanup code in Dispose(ByVal disposing As Boolean) above. ' Dispose(False) ' MyBase.Finalize() 'End Sub ' This code added by Visual Basic to correctly implement the disposable pattern. Public Sub Dispose() Implements IDisposable.Dispose ' Do not change this code. Put cleanup code in Dispose(disposing As Boolean) above. Dispose(True) GC.SuppressFinalize(Me) End Sub #End Region End Class End Namespace
Hope you find this useful !!!
Leave a Reply
You must be logged in to post a comment.