Estimated Time 45 Minutes
Silverlight out-of-browser enables you to create desktop applications. Using elevated trust further opens the possibilities of what your application can do. This lab is designed to further explore what can be down with an out-of-browser Silverlight application.
In the lab you'll create an application that imports data directly from Excel. Along the way you'll learn how to interact with the hard drive, check for updates, and work with Excel from Silverlight.
You'll start by dragging and dropping Excel files onto the application. Next, you’ll call Excel through the AutomationFactory and process the data. You’ll create files and directories on the hard drive to store temporary data. Finally, you’ll learn how to check for application updates. The Silverlight application that you'll create is shown next:
This first section shows how to enable a drop area where an Excel file will be dropped. The next section shows how to open the dropped Excel file and read its data.
Before getting started, copy and paste the four excel files found in the zip file in to your My Documents folder. Since Silverlight has limited file access you’ll need to put these files in a place where Silverlight can work with them. Later in this lab you’ll learn how to overcome this limitation by creating a temp directory and file from Silverlight.
public DataWidget()
{
// Required to initialize variables
InitializeComponent();
this.Data = new ObservableCollection<YearValueData>();
this.ImportPanel.AllowDrop = true;
this.ImportPanel.Drop += new DragEventHandler(ImportPanel_Drop);
}
Public Sub New()
' Required to initialize variables
InitializeComponent()
Me.Data = New ObservableCollection(Of YearValueData)()
AddHandler ImportPanel.Drop, AddressOf ImportPanel_Drop
End Sub
Private Sub ImportPanel_Drop(ByVal sender As Object, ByVal e As DragEventArgs)
If e.Data IsNot Nothing Then
Dim files() As FileInfo = TryCast(e.Data.GetData(DataFormats.FileDrop), FileInfo())
End If
End Sub
As a developer it’s imperative to know how to work with tools that businesses rely on. Microsoft Excel is a tool frequently requested to have applications integrated with. With the out-of-browser feature in Silverlight, you’re able to call Excel methods, which include working with data contained inside.
In this exercise you’ll use the AutomationFactory to open an instance of Excel, open the first Worksheet, and loop through the content. The starter solution is already configured to make use of the AutomationFactory, however if you’re working on your own solution, you must first ensure the application has elevated trusted enabled. You can toggle this setting from the Out-of-browser settings in the Project’s Properties panel.
// Get the first dropped file
var fi = files[0];
// Create the Excel object
dynamic excel = AutomationFactory.CreateObject("Excel.Application");
// Open the excel document. Must be located in "My Documents"
dynamic excelWorkBook = excel.Workbooks.Open(string.Format("{0}\\{1}",
Environment.GetFolderPath(
Environment.SpecialFolder.MyDocuments),fi.Name));
// Read the Worksheet
dynamic activeWorkSheet = excelWorkBook.ActiveSheet();
Dim fi = files(0)
Dim excel As Object
Try
' Check to see if Excel is already running
excel = AutomationFactory.GetObject("Excel.Application")
Catch
excel = AutomationFactory.CreateObject("Excel.Application")
End Try
' Open the excel document
Dim excelWorkBook As Object = excel.Workbooks.Open(String.Format("{0}\\{1}",
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), fi.Name))
' Read the Worksheet
Dim activeWorkSheet As Object = excelWorkBook.ActiveSheet()
// Cells to Read
dynamic cell1, cell2;
// Iterate through Cells
for (int count = 3; count < 30; count++)
{
cell1 = activeWorkSheet.Cells[count, 1];
cell2 = activeWorkSheet.Cells[count, 2];
Data.Add(new YearValueData()
{
Year = cell1.Value,
Value = cell2.Value
});
}
' Cells to Read
Dim cell1, cell2 As Object
' Iterate through Cells
For count As Integer = 3 To 29
cell1 = activeWorkSheet.Cells(count, 1)
cell2 = activeWorkSheet.Cells(count, 2)
Data.Add(New YearValueData() With {.Year = cell1.Value, .Value = cell2.Value})
Next count
// Title is a TextBlock in XAML, this sets the value Title.Text = activeWorkSheet.Cells[1, 1].Value;
'Title is a TextBlock in XAML, this sets the value Title.Text = activeWorkSheet.Cells(1, 1).Value
// Close the workbook excelWorkBook.Close(); // Close the Excel process excel.Quit();
' Close the workbook excelWorkBook.Close() ' Close the Excel process excel.Quit()
// Populate the DataGrid
ExcelDataGrid.ItemsSource = this.Data;
// Create LineSeries
LineSeries lineSeries = new LineSeries();
lineSeries.ItemsSource = this.Data;
lineSeries.IndependentValueBinding = new Binding("Year");
lineSeries.DependentValueBinding = new Binding("Value");
this.Chart.Series.Add(lineSeries);
' Populate the DataGrid
ExcelDataGrid.ItemsSource = Me.Data
' Create LineSeries
Dim lineSeries As New LineSeries()
lineSeries.ItemsSource = Me.Data
lineSeries.IndependentValueBinding = New Binding("Year")
lineSeries.DependentValueBinding = New Binding("Value")
Me.Chart.Series.Add(lineSeries)
void ImportPanel_Drop(object sender, DragEventArgs e)
{
if (e.Data != null)
{
FileInfo[] files = e.Data.GetData(DataFormats.FileDrop) as FileInfo[];
if (AutomationFactory.IsAvailable)
{
// Get the first file
var fi = files[0];
// Create the Excel object
dynamic excel = AutomationFactory.CreateObject("Excel.Application");
// Open the excel document. Must be located in "My Documents"
dynamic excelWorkBook = excel.Workbooks.Open(string.Format("{0}\\{1}",
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),fi.Name));
// Read the Worksheet
dynamic activeWorkSheet = excelWorkBook.ActiveSheet();
// Cells to Read
dynamic cell1, cell2;
// Iterate through Cells
for (int count = 3; count < 30; count++)
{
cell1 = activeWorkSheet.Cells[count, 1];
cell2 = activeWorkSheet.Cells[count, 2];
Data.Add(new YearValueData()
{
Year = cell1.Value,
Value = cell2.Value
});
}
// Title is a TextBlock in XAML, this sets the value
Title.Text = activeWorkSheet.Cells[1, 1].Value;
// Close the workbook
excelWorkBook.Close();
// Close the Excel process
excel.Quit();
// Populate the DataGrid
ExcelDataGrid.ItemsSource = this.Data;
// Create LineSeries
LineSeries lineSeries = new LineSeries();
lineSeries.ItemsSource = this.Data;
lineSeries.IndependentValueBinding = new Binding("Year");
lineSeries.DependentValueBinding = new Binding("Value");
this.Chart.Series.Add(lineSeries);
}
}
}
Private Sub ImportPanel_Drop(ByVal sender As Object, ByVal e As DragEventArgs)
If e.Data IsNot Nothing Then
Dim files() As FileInfo = TryCast(e.Data.GetData(DataFormats.FileDrop), FileInfo())
Dim fi = files(0)
Dim excel As Object
Try
' Check to see if Excel is already running
excel = AutomationFactory.GetObject("Excel.Application")
Catch
excel = AutomationFactory.CreateObject("Excel.Application")
End Try
' Open the excel document
Dim excelWorkBook As Object = excel.Workbooks.Open(String.Format("{0}\\{1}", Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), fi.Name))
' Read the Worksheet
Dim activeWorkSheet As Object = excelWorkBook.ActiveSheet()
' Cells to Read
Dim cell1, cell2 As Object
' Iterate through Cells
For count As Integer = 3 To 29
cell1 = activeWorkSheet.Cells(count, 1)
cell2 = activeWorkSheet.Cells(count, 2)
Data.Add(New YearValueData() With {.Year = cell1.Value, .Value = cell2.Value})
Next count
'Title is a TextBlock in XAML, this sets the value
Title.Text = activeWorkSheet.Cells(1, 1).Value
' Close the workbook
excelWorkBook.Close()
' Close the Excel process
excel.Quit()
' Populate the DataGrid
ExcelDataGrid.ItemsSource = Me.Data
' Create LineSeries
Dim lineSeries As New LineSeries()
lineSeries.ItemsSource = Me.Data
lineSeries.IndependentValueBinding = New Binding("Year")
lineSeries.DependentValueBinding = New Binding("Value")
Me.Chart.Series.Add(lineSeries)
End If
End Sub
Working with object via AutomationFactory, can be challenging. Unfortunately there is no intellisence helping out, so you must rely on documentation. Here are the coding documents that will help when working with Excel. Excel 2007 Developer Reference Excel 2010 Developer Reference
When running in a trusted environment, you can access only files in user folders, specifically the MyDocuments, MyMusic, MyPictures, and MyVideos folders. Although this makes sense from a security point of view, it’s limiting. You want to enable the user to drag their data from any location. As it stands right now, if you try to drop a file from a location other than stated above, Silverlight will throw a security error.
In this section we’re going to cover how to import an Excel file from anywhere on the hard drive, how to create and delete directories, and how to create and modify files. Before you begin it’s important to lay out exactly what needs to be done.
private bool CopyFileToTempDirectory(FileInfo fi, string tempDirectory, string fileName)
{
using (Stream stream = fi.OpenRead())
{
try
{
byte[] buffer = new byte[Convert.ToInt32(stream.Length)];
stream.Read(buffer, 0, Convert.ToInt32(stream.Length));
stream.Close();
// Create a temporary directory in My Documents
Directory.CreateDirectory(tempDirectory);
// Write a new file to the temp directory
File.WriteAllBytes(string.Format("{0}\\{1}", tempDirectory, fileName), buffer);
return true;
}
catch (Exception e)
{
return false;
}
}
}
Private Function CopyFileToTempDirectory(ByVal fi As FileInfo, ByVal tempDirectory As String, ByVal fileName As String) As Boolean
Using stream_Renamed As Stream = fi.OpenRead()
Try
' Copy file to My Documents. This ensures we can open it up in Excel
Dim buffer(Convert.ToInt32(stream_Renamed.Length) - 1) As Byte
stream_Renamed.Read(buffer, 0, Convert.ToInt32(stream_Renamed.Length))
stream_Renamed.Close()
' Create a temporary directory in My Documents
Directory.CreateDirectory(tempDirectory)
' Write a new file to the temp directory
File.WriteAllBytes(String.Format("{0}\{1}", tempDirectory, fileName), buffer)
Return True
Catch e As Exception
Return False
End Try
End Using
End Function
void ImportPanel_Drop(object sender, DragEventArgs e)
{
// ...
string myDocuments = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
string tempDirectory = string.Format("{0}\\temp", myDocuments);
string tempFullPath = string.Format("{0}\\{1}", tempDirectory, fi.Name);
// Copy the file to a temp directory in My Documents
CopyFileToTempDirectory(fi, tempDirectory, fi.Name);
// Create the Excel object
dynamic excel = AutomationFactory.CreateObject("Excel.Application");
dynamic excelWorkBook = excel.Workbooks.Open(tempFullPath);
// ...
}
Private Sub ImportPanel_Drop(ByVal sender As Object, ByVal e As DragEventArgs)
'...
Dim myDocuments As String = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
Dim tempDirectory As String = String.Format("{0}\temp", myDocuments)
Dim tempFullPath As String = String.Format("{0}\{1}", tempDirectory, fi.Name)
' Copy the file to a temp directory in My Documents
CopyFileToTempDirectory(fi, tempDirectory, fi.Name)
'Dim result = New ObservableCollection(Of YearValueData)()
Dim excel As Object
Try
' Check to see if Excel is already running
excel = AutomationFactory.GetObject("Excel.Application")
Catch
excel = AutomationFactory.CreateObject("Excel.Application")
End Try
' Open the excel document
Dim excelWorkBook As Object = excel.Workbooks.Open(tempFullPath)
'...
End Sub
private void CleanUpFileSystem(string tempDirectory, string tempFullPath)
{
File.Delete(tempFullPath);
// Remove temp directory
Directory.Delete(tempDirectory + "\\", true);
}
Private Sub CleanUpFileSystem(ByVal tempDirectory As String, ByVal tempFullPath As String)
File.Delete(tempFullPath)
' Remove temp directory
Directory.Delete(tempDirectory & "\", True)
End Sub
void ImportPanel_Drop(object sender, DragEventArgs e)
{
if (e.Data != null)
{
FileInfo[] files = e.Data.GetData(DataFormats.FileDrop) as FileInfo[];
if (AutomationFactory.IsAvailable)
{
// Get the first file
var fi = files[0];
string myDocuments = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
string tempDirectory = string.Format("{0}\\temp", myDocuments);
string tempFullPath = string.Format("{0}\\{1}", tempDirectory, fi.Name);
// Copy the file to a temp directory in My Documents
CopyFileToTempDirectory(fi, tempDirectory, fi.Name);
// Create the Excel object
dynamic excel = AutomationFactory.CreateObject("Excel.Application");
// Open the excel document. Must be located in "My Documents"
dynamic excelWorkBook = excel.Workbooks.Open(tempFullPath);
// Read the Worksheet
dynamic activeWorkSheet = excelWorkBook.ActiveSheet();
// Cells to Read
dynamic cell1, cell2;
// Iterate through Cells
for (int count = 3; count < 30; count++)
{
cell1 = activeWorkSheet.Cells[count, 1];
cell2 = activeWorkSheet.Cells[count, 2];
Data.Add(new YearValueData(){
Year = cell1.Value,
Value = cell2.Value
});
}
// Title is a TextBlock in XAML, this sets the value
Title.Text = activeWorkSheet.Cells[1, 1].Value;
// Close the workbook
excelWorkBook.Close();
// Close the Excel process
excel.Quit();
CleanUpFileSystem(tempDirectory, tempFullPath);
// Populate the DataGrid
ExcelDataGrid.ItemsSource = this.Data;
// Create LineSeries
LineSeries lineSeries = new LineSeries();
lineSeries.ItemsSource = this.Data;
lineSeries.IndependentValueBinding = new Binding("Year");
lineSeries.DependentValueBinding = new Binding("Value");
this.Chart.Series.Add(lineSeries);
// Hide the ImportPanel
this.ImportPanel.Visibility = Visibility.Collapsed;
}
}
}
Private Sub ImportPanel_Drop(ByVal sender As Object, ByVal e As DragEventArgs)
If e.Data IsNot Nothing Then
Dim files() As FileInfo = TryCast(e.Data.GetData(DataFormats.FileDrop), FileInfo())
If files.Length > 0 Then
If AutomationFactory.IsAvailable Then
Dim fi = files(0)
If fi.Name.ToLower().Contains(".xls") OrElse fi.Name.ToLower().Contains(".xlsx") Then
VisualStateManager.GoToState(Me, "Loading", True)
Dim myDocuments As String = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
Dim tempDirectory As String = String.Format("{0}\temp", myDocuments)
Dim tempFullPath As String = String.Format("{0}\{1}", tempDirectory, fi.Name)
' Copy the file to a temp directory in My Documents
CopyFileToTempDirectory(fi, tempDirectory, fi.Name)
'Dim result = New ObservableCollection(Of YearValueData)()
Dim excel As Object
Try
' Check to see if Excel is already running
excel = AutomationFactory.GetObject("Excel.Application")
Catch
excel = AutomationFactory.CreateObject("Excel.Application")
End Try
' Open the excel document
Dim excelWorkBook As Object = excel.Workbooks.Open(tempFullPath)
' Read the Worksheet
Dim activeWorkSheet As Object = excelWorkBook.ActiveSheet()
' Cells to Read
Dim cell1, cell2 As Object
Title.Text = activeWorkSheet.Cells(1, 1).Value
' Iterate through Cells
For count As Integer = 3 To 29
cell1 = activeWorkSheet.Cells(count, 1)
cell2 = activeWorkSheet.Cells(count, 2)
Me.Data.Add(New YearValueData() With {.Year = cell1.Value, .Value = cell2.Value})
Next count
' Close the workbook
excelWorkBook.Close()
' Close the Excel process
excel.Quit()
' Clean up temp file
CleanUpFileSystem(tempDirectory, tempFullPath)
' Populate the DataGrid
ExcelDataGrid.ItemsSource = Me.Data
' Create LineSeries
Dim lineSeries As New LineSeries()
lineSeries.ItemsSource = Me.Data
lineSeries.IndependentValueBinding = New Binding("Year")
lineSeries.DependentValueBinding = New Binding("Value")
Me.Chart.Series.Add(lineSeries)
VisualStateManager.GoToState(Me, "DetailsState", True)
Else
' Display error: "Hey this isn't an Excel file, please select valid excel file"
End If
End If
End If
End If
End Sub
At this point you’ve learned how to read Excel data, open files from anywhere in the hard drive, and work with the hard drive. Moving away working with data, a situation that needs consideration is how do you check for updates in an out-of-browser scenario. This exercise covers how to check if there are updates.
public MainPage()
{
InitializeComponent();
this.CheckForUpdatesButton.Click += new RoutedEventHandler(CheckForUpdatesButton_Click);
}
Public Sub New()
InitializeComponent()
AddHandler CheckForUpdatesButton.Click, AddressOf CheckForUpdatesButton_Click
End Sub
void CheckForUpdatesButton_Click(object sender, RoutedEventArgs e)
{
Application.Current.CheckAndDownloadUpdateAsync();
Application.Current.CheckAndDownloadUpdateCompleted += new CheckAndDownloadUpdateCompletedEventHandler(Current_CheckAndDownloadUpdateCompleted);
}
Private Sub CheckForUpdatesButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
Application.Current.CheckAndDownloadUpdateAsync()
AddHandler Application.Current.CheckAndDownloadUpdateCompleted, AddressOf Current_CheckAndDownloadUpdateCompleted
End Sub
void Current_CheckAndDownloadUpdateCompleted(object sender, CheckAndDownloadUpdateCompletedEventArgs e)
{
if (e.UpdateAvailable)
{
MessageBox.Show("An application update has been downloaded. " +
"Restart the application to run the new version.");
}
else if (e.Error != null)
{
MessageBox.Show(
"An application update is available, but an error has occurred.\n" +
"This can happen, for example, when the update requires\n" +
"a new version of Silverlight or requires elevated trust.\n" +
"To install the update, visit the application home page.");
// LogErrorToServer(e.Error);
}
else
{
MessageBox.Show("There is no update available.");
}
}
Private Sub Current_CheckAndDownloadUpdateCompleted(ByVal sender As Object, ByVal e As CheckAndDownloadUpdateCompletedEventArgs)
If e.UpdateAvailable Then
MessageBox.Show("An application update has been downloaded. " & "Restart the application to run the new version.")
ElseIf e.Error IsNot Nothing Then
MessageBox.Show("An application update is available, but an error has occurred." & vbLf & "This can happen, for example, when the update
requires" & vbLf & "a new version of Silverlight or requires elevated trust."
& vbLf & "To install the update, visit the application home page.")
'LogErrorToServer(e.Error);
Else
MessageBox.Show("There is no update available.")
End If
End Sub
In this exercise you examined advanced features of Silverlight’s out-of-browser feature. You learned how to open an Excel file from anywhere on the hard drive by writing its content to a temporary directory. From there, Silverlight read the data from the worksheet and displayed it to a grid and chart. The application satisfied the following requirements:
This lab provided the building blocks on how to out-of-browser in a business setting. By applying skills learned from previous labs, you should now be able to read in the data, create a WCF service, and send the imported data to be stored on the server.
Comments (0)