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); 
  }
}
comments powered by Disqus

Featured

  • Visual Studio 2026 Gives Copilot Built-In Skills -- and Makes Them Prove Their Worth

    Microsoft is moving Agent Skills beyond bring-your-own instructions by shipping expert-authored workflows with the IDE, while keeping them off by default until testing shows their benefits justify the additional token use.

  • Copilot AI Billing Shock Met with Meters, Caps and Token-Saving Tools

    GitHub is layering spending limits, expanded credit allowances and increasingly granular usage reporting onto Copilot, while Microsoft is reworking Visual Studio and VS Code to expose -- and reduce -- the cost of agentic development.

  • The AI-Powered Software Development Lifecycle

    René van Osnabrugge makes the case that AI's biggest opportunity in software development is not faster coding -- it's reducing the friction everywhere else in the SDLC.

  • Copilot Usage-Based Billing Gets a Token Dashboard

    Microsoft is keeping Visual Studio's new built-in Agent Skills switched off by default while a public dashboard measures whether their performance gains justify the additional tokens they may consume.

Subscribe on YouTube