I upload and download Word files in my web application. I followed two articles to help me make this possible:
How Do I: Import and Store a Data File (this one only discusses uploads but the process is similar)
Upload and download file in Lightswitch 2011
In my solution, both upload and download follow the pattern in the first article for symmetry's sake. I didn't really care for the way the second article handled the download side. I can't remember exactly if the references mentioned in the second article are necessary for the way I did things. I have those references in my project but I know I use them for other things. And in VS2013 at least, the unloading and reloading of the project was not necessary.
Essentially, you need to create a custom Silverlight control to add this functionality. So add an .xaml
file to your User Code. Both articles have examples of what should be in there and mine looks like this:
<controls:ChildWindow x:Class="LightSwitchApplication.DownloadFileWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
Width="380" Height="125"
Title="Select Where to Save File" >
<Grid x:Name="LayoutRoot" Margin="2">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Button x:Name="CancelButton" Content="Cancel" Click="CancelButton_Click" Width="75" Height="25" HorizontalAlignment="Right" Margin="0,15,0,0" Grid.Row="1" />
<Button x:Name="OKButton" Content="OK" Click="OKButton_Click" Width="75" Height="25" HorizontalAlignment="Right" Margin="0,15,80,0" Grid.Row="1" />
<Button Content="Browse" Height="25" HorizontalAlignment="Left" Margin="275,10,0,0" Name="BrowseButton" VerticalAlignment="Top" Width="75" Click="BrowseButton_Click" />
<TextBox Height="25" HorizontalAlignment="Left" Margin="10,10,0,0" Name="FileTextBox" VerticalAlignment="Top" Width="250" IsEnabled="True"/>
</Grid>
</controls:ChildWindow>
VS2013 (which I'm using) and LightSwitch 2011 (which is what the articles are written for) handle the code behind the .xaml
differently. I'm not sure how VS2012 handles it so you'll need to figure that part out. But in the code behind your custom Silverlight control, you need a constructor, functions that set this.DialogResult
to true
and false
for the OK and Cancel buttons, respectively, and three properties:
- a
DocumentStream
as a MemoryStream
type to write the file to your computer
- a
SaveFileStream
as a FileStream
type to pull the file from the database
- a
FileName
as a String
type
The real work of saving the file takes place in the code for the Browse button.
private void BrowseButton_Click(object sender, RoutedEventArgs e) {
SaveFileDialog saveFileDialog = new SaveFileDialog();
saveFileDialog.Filter = "Word Files (*.docx)|*.docx|(*.docm)|*.docm";
saveFileDialog.DefaultExt = "docx";
if ((saveFileDialog.ShowDialog() == true)) {
// Get File name, store and display to user
this.FileTextBox.Text = saveFileDialog.FileName;
this.m_FileName = saveFileDialog.FileName;
this.FileTextBox.IsReadOnly = true;
try {
// Open and store the File Stream
this.DocumentStream = saveFileDialog.OpenFile();
}
catch (IOException ex) {
// Inform the user of the problem
MessageBox.Show("The file you are trying to save to is open in another applicaion." + "\r\n" + "Please close it and try again.", "File Already Open", MessageBoxButton.OK);
}
}
}
I have the Filter
and DefaultExt
set to handle Word docs but you can modify this to handle .txt
or whatever you want. I've also added a bit more error handling than the examples in the articles based on my experiences using it.
Finally, in your screen code, you need invoke the custom control on the Main
dispatcher and write the file to the database when the custom control closes.
partial void DownloadFile_Execute()
{
// To invoke our own dialog, we have to do this inside of the "Main" Dispatcher
// And, since this is a web application, we can't directly invoke the Silverlight OpenFileDialog
// class, we have to first invoke our own Silverlight custom control (i.e. DownloadFileWindow)
// and that control will be able to invoke the OpenFileDialog class (via the Browse button)
Dispatchers.Main.BeginInvoke(() =>
{
DownloadFileWindow downloadFileWindow = new DownloadFileWindow();
downloadFileWindow.Closed += new EventHandler(downloadFileWindow_Closed);
downloadFileWindow.Show();
});
}
void downloadFileWindow_Closed(object sender, EventArgs e)
{
// Invoked when our custom Silverlight window closes
DownloadFileWindow downloadFile = (DownloadFileWindow)sender;
try {
// Continue if they hit the OK button AND they selected a file
if ((downloadFile.DialogResult == true)) {
// Write the document data stream from the database to the selected file
using (Stream saveStream = new Stream(downloadFile.DocumentStream))
{
downloadFile.DocumentStream.WriteTo(saveStream);
}
}
// Close and release the streams
downloadFile.DocumentStream.Close();
downloadFile.DocumentStream.Dispose();
downloadFile.SaveFileStream.Close();
downloadFile.SaveFileStream.Dispose();
}
catch (Exception ex) {
string res = "One or more save location errors have occured:" + "\r\n";
// Check to see if there is a Document Stream
if ((downloadFile.DocumentStream == null)) {
res = res + '\t' + "Document Stream is empty" + "\r\n";
}
// Check to see if there is a Save File Stream
if ((downloadFile.SaveFileStream == null)) {
res = res + '\t' + "Save File Stream is empty" + "\r\n";
}
// Check to see if there is a Safe File Name
if ((downloadFile.SafeFileName == null)) {
res = res + '\t' + "Safe File Name is empty" + "\r\n";
}
res = res + "\r\n" + "Please use the Browse button to select a location to save to. Specify a file name and then click Save.";
this.ShowMessageBox(res, "Save Location Error", MessageBoxOption.Ok);
}
}
As you can see, I've added a lot more error handling to these functions as well, based on experience. Hopefully between the two articles and my examples you can create the functionality that you want.
Note: I converted the code from VB.NET which is what my project is written in. So there may be errors that you have to correct for to make the syntax correct for C#.