Using MEF to Expose Interfaces in Your Silverlight MVVM Apps: Listing 3
Custom INavigationContentLoader
[Export] public class CompositionNavigationContentLoader :
INavigationContentLoader {
[ImportMany(typeof(IView))]
public IEnumerable<ExportFactory<IView, IViewMetadata>>
ViewExports { get; set; }
[ImportMany(typeof(IViewModel))]
public IEnumerable<ExportFactory<IViewModel, IViewModelMetadata>>
ViewModelExports { get; set; }
public bool CanLoad(Uri targetUri, Uri currentUri) {
return true;
}
public void CancelLoad(IAsyncResult asyncResult) {
return;
}
public IAsyncResult BeginLoad(Uri targetUri, Uri currentUri,
AsyncCallback userCallback, object asyncState) {
// Convert to a dummy relative Uri so we can access the host.
var relativeUri = new Uri("http://" + targetUri.OriginalString,
UriKind.Absolute);
// Get the factory for the ViewModel.
var viewModelMapping = ViewModelExports.FirstOrDefault(o =>
o.Metadata.Key.Equals(relativeUri.Host,
StringComparison.OrdinalIgnoreCase));
if (viewModelMapping == null)
throw new InvalidOperationException(
String.Format("Unable to navigate to: {0}. " +
"Could not locate the ViewModel.",
targetUri.OriginalString));
// Get the factory for the View.
var viewMapping = ViewExports.FirstOrDefault(o =>
o.Metadata.ViewModelContract ==
viewModelMapping.Metadata.ViewModelContract);
if (viewMapping == null)
throw new InvalidOperationException(
String.Format("Unable to navigate to: {0}. " +
"Could not locate the View.",
targetUri.OriginalString));
// Resolve both the View and the ViewModel.
var viewFactory = viewMapping.CreateExport();
var view = viewFactory.Value as Control;
var viewModelFactory = viewModelMapping.CreateExport();
var viewModel = viewModelFactory.Value as IViewModel;
// Attach ViewModel to View.
view.DataContext = viewModel;
viewModel.OnLoaded();
// Get navigation values.
var values = viewModelMapping.Metadata.GetArgumentValues(targetUri);
viewModel.OnNavigated(values);
if (view is Page) {
Page page = view as Page;
page.Title = viewModel.GetTitle();
}
else if (view is ChildWindow) {
ChildWindow window = view as ChildWindow;
window.Title = viewModel.GetTitle();
}
// Do not navigate if it's a ChildWindow.
if (view is ChildWindow) {
ProcessChildWindow(view as ChildWindow, viewModel);
return null;
}
else {
// Navigate because it's a Control.
var result = new CompositionNavigationAsyncResult(asyncState, view);
userCallback(result);
return result;
}
}
private void ProcessChildWindow(ChildWindow window,
IViewModel viewModel) {
// Close the ChildWindow if the ViewModel requests it.
var closableViewModel = viewModel as IClosableViewModel;
if (closableViewModel != null) {
closableViewModel.CloseView += (s, e) => { window.Close(); };
}
// Show the window.
window.Show();
}
public LoadResult EndLoad(IAsyncResult asyncResult) {
return new LoadResult((asyncResult as
CompositionNavigationAsyncResult).Result);
}
}