Kevin, thank you for sharing this great tool with us. Awsome!David, I have encountered the same exception, and fixing it wasn't as straight forward as catching the error, so I have decided to share my solution and the sources I have used. Maybe someone will come with a better one. There seems to be a bug in Silverlight's SaveFileStream, which is discussed in greater details here: http://betaforums.silverlight.net/forums/p/176869/440957.aspxI have also noticed that silverPDF is a pretty big library. My .xap jumped to 990 KB from 140 KB just by adding it as reference. And of course this affects the loading time of the application. To avoid this I have implemented a dynamic loading on demand of this library when the user decides to create a PDF. Here is the article I have followed:http://msdn.microsoft.com/en-us/library/cc903931(VS.95).aspxAnd this is my final code:#region PDF creation
AssemblyPart apSilverPDF;
System.IO.Stream PDFStream;
/// <summary>
/// Handle "Create PDF" button click
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Button_Click(object sender, RoutedEventArgs e)
{
LoadPDFLibraryAndSaveFile();
}
/// <summary>
/// Load the silverPDF library if it hasn't been loaded already
/// or use the library if already loaded
/// </summary>
private void LoadPDFLibraryAndSaveFile()
{
SaveFileDialog savePDF = new SaveFileDialog();
savePDF.Filter = "PDF file format|*.pdf";
savePDF.DefaultExt = ".pdf";
if (savePDF.ShowDialog() == true)
{
//catch the error if the user tries to save over a file that is currently open
try
{
PDFStream = savePDF.OpenFile();
//if silverPDF library is not loaded already, load it
if (apSilverPDF == null)
{
LoadPDFLibrary();
}
else
{
//if the library is loaded, just save the PDF file
SavePDF();
}
}
catch (IOException ioe)
{
//tell the user the file is open
MessageBox.Show("Selected PDF file is open. Close the file and try again!", "Open File Error", MessageBoxButton.OK);
}
}
}
/// <summary>
/// Send a request to load the silverPDF library dynamically
/// </summary>
private void LoadPDFLibrary()
{
WebClient client = new WebClient();
client.OpenReadCompleted += new OpenReadCompletedEventHandler(client_OpenReadCompleted);
client.OpenReadAsync(new Uri("silverPDF.dll", UriKind.Relative));
}
/// <summary>
/// Load the library and use it to create the PDF
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void client_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
if ((e.Error == null) && (e.Cancelled == false))
{
apSilverPDF = new AssemblyPart();
apSilverPDF.Load(e.Result);
SavePDF();
}
else
{
MessageBox.Show("There was a problem loading PDF Library", "PDF Library Loading Error", MessageBoxButton.OK);
}
}
/// <summary>
/// Save the PDF File
/// </summary>
private void SavePDF()
{
PDFExporter PDFNew = new PDFExporter();
//add map to the PDF
PDFNew.SetMap(Map);
//add navigation with scale bar to the PDF
PDFNew.AddElement(navigationGrid);
PDFNew.SetOutputStream(PDFStream);
PDFNew.DoExport();
}
#endregion
And in App.xaml.cs:
private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
{
// If the app is running outside of the debugger then report the exception using
// the browser's exception mechanism. On IE this will display it a yellow alert
// icon in the status bar and Firefox will display a script error.
if (!System.Diagnostics.Debugger.IsAttached)
{
// NOTE: This will allow the application to continue running after an exception has been thrown
// but not handled.
// For production applications this error handling should be replaced with something that will
// report the error to the website and stop the application.
e.Handled = true;
//This is required to swallow an error when saving a file over a file that is open.
//This is a bug, and application crashes if this line is not there.
if (e.ExceptionObject.StackTrace.IndexOf("SaveFileStream") != -1) return;
Deployment.Current.Dispatcher.BeginInvoke(delegate { ReportErrorToDOM(e); });
}
}