We’ve been working on a Silverlight project that could be classified as a Line Of Business application (whatever that means).
There have been a few places where we need to allow users to save files. First, I thought I might give you a peek as to how we do this with Caliburn .
Imagine that we are displaying a table of data and that we are allowing the user to export that data to a csv file and save it to their desktop.
How We Do It
In the view, I have a button that looks like this:
<Button pf:Message.Attach="Export"
Content="Export Data">
pf is defined as
xmlns:pf="clr-namespace:Caliburn.PresentationFramework;assembly=Caliburn.PresentationFramework"
You can read more about Message.Attach in the Caliburn documentation.
The view is associated with a view model, and that view model has a method:
public IEnumerable<IResult> Export()
{
var saveFileResult = new SaveFile { DefaultExt = "csv" };
yield return saveFileResult;
if (saveFileResult.FileStream == null) yield break; //null means the user clicked ‘Cancel’
var content = FormatAsCsv();
using (var writer = new StreamWriter(saveFileResult.FileStream))
{
writer.Write(content);
Caliburn.Core.Invocation.Execute.OnUIThread(writer.Close);
}
}
The Message.Attach in the view binds the button to this method on our view model. IResult is a poor man’s coroutine and you can read more about it here.
It’s not that obvious when discussing the save file scenario, but this approach is really useful when dealing with asynchronous actions, such as interacting with a web service. Also by using the SaveFile abstraction, we could more easily test this method. (Though newing it up here sort of nullifies that, but I digress.)
But what is the SaveFile class anyway?
public class SaveFile : IResult
{
public string Filter { get; set; }
public string DefaultExt { get; set; }
public string SafeFileName { get; private set; }
public Stream FileStream { get; private set; }
public void Execute(IRoutedMessageWithOutcome message, IInteractionNode handlingNode)
{
var dlg = new SaveFileDialog
{
Filter = Filter,
DefaultExt = DefaultExt,
};
if (dlg.ShowDialog().GetValueOrDefault(false))
{
FileStream = dlg.OpenFile();
SafeFileName = dlg.SafeFileName;
}
Completed(this, null);
}
public event Action<IResult,Exception> Completed = delegate { };
}
It a simple abstract for opening and managing the SaveFileDialog. If you want to know more, check out the Caliburn documentation and sample (or harass Rob Eisenberg to post more). Rob also had an introductory post on IResult.
Coming Soon
My rant about Silverlight’s inadequate SaveFileDialog.
Posted
09-25-2009 3:30 PM
by
Christopher Bennage