Dieser Artikel wurde maschinell übersetzt.

Silverlight verfügbar

Machen Sie mit MEF Schnittstellen in Ihren Silverlight MVVM-Anwendungen verfügbar

Sandrino Di Di

Downloaden des Codebeispiels

Während viele Entwickler Silverlight als Web-zentrierten Technologie vorstellen können, ist in der Praxis es eine hervorragende Plattform für die Erstellung von jede Art von Anwendung geworden. Silverlight verfügt über integrierte Unterstützung für Konzepte wie Datenbindung, Wertkonverter, Navigation, Vorgang außerhalb des Browsers und COM-Interop, wodurch es relativ einfach, alle Arten von Anwendungen zu erstellen. Und wenn ich alle Arten von sagen, ich auch Enterprise-Anwendungen bedeuten.

Erstellen eine Silverlight-Anwendung mit dem Muster Model-View-ViewModel (MVVM) können Sie, zusätzlich zu den Funktionen bereits in Silverlight, die Vorteile der bessere Wartbarkeit Testbarkeit und Trennung der Benutzeroberfläche von der Logik. Und selbstverständlich müssen Sie nicht alle diese selbst herausfinden. Es gibt eine Fülle von Informationen und Tools draußen, um Ihnen den Einstieg zu erleichtern. Z. B. MVVM Light-Toolkit (mvvmlight.codeplex.com ) ist ein einfaches Framework zum Implementieren von MVVM mit Silverlight und Windows Presentation Foundation (WPF) und WCF RIA-Dienste (silverlight.net/getstarted/riaservices ) hilft Ihnen, problemlos auf Windows Communication Foundation (WCF) Dienste und Datenbanken Dank für die Codegenerierung zugreifen.

Sie können Ihre Silverlight-Anwendung einen weiteren Schritt mit dem verwalteten Erweiterbarkeit Framework ( mef.codeplex.com ), auch bekannt als MEF nutzen. Dieses Framework bietet die Grundlagen, um erweiterbare Anwendungen, Komponenten und Komposition zu erstellen.

Im Rest dieses Artikels werde wie MEF verwendet wird, erhalten Sie die zentralen Verwaltung der Erstellung anzeigen und ViewModel aufgezeigt. Sobald Sie dies haben, können Sie weitere als nur in den DataContext des der Ansicht eine ViewModel wechseln. Dies alles erfolgt durch Anpassen des integrierten Silverlight-Navigation. Zu einem angegebenen URL navigiert, fängt diese Anforderung MEF, untersucht die Route (etwas wie ASP.NET MVC), sucht nach einer übereinstimmenden anzeigen und ViewModel, benachrichtigt der ViewModel, was geschieht, und die Ansicht zeigt.

Erste Schritte mit MEF

Da MEF das Datenbankmodul, das alle Teile in diesem Beispiel wird eine Verbindung herstellt, empfiehlt es sich, ihn zu starten. Wenn Sie nicht mit MEF bereits vertraut sind, zuerst lesen Glenn Block des Artikels “ Building zusammenstellbar Anwendungen im .NET 4 mit verwalteten Erweiterbarkeit Framework, ” in der Ausgabe vom Februar 2010 MSDN Magazin (msdn.microsoft.com/magazine/ee291628 ).

Zunächst müssen Sie MEF beim Starten der Anwendung durch Behandeln des Startup-Ereignis des App-Klasse korrekt zu konfigurieren:

private void OnStart(object sender, StartupEventArgs e) {
  // Initialize the container using a deployment catalog.
var catalog = new DeploymentCatalog();
  var container = CompositionHost.Initialize(catalog);
  // Export the container as singleton.
container.ComposeExportedValue<CompositionContainer>(container);
  // Make sure the MainView is imported.
CompositionInitializer.SatisfyImports(this);
}

Der Katalog Bereitstellung stellt sicher, alle Assemblys für Exporte durchsucht, und anschließend wird mit einer CompositionContainer erstellen. Da die Navigation dieses Containers einige Arbeit, die später dazu benötigt wird, ist es wichtig, die Instanz dieses Containers als exportierte Wert zu registrieren. Dadurch wird den gleichen Container importiert werden sollen, wenn erforderlich.

Eine andere Möglichkeit wäre, den Container als statisches Objekt zu speichern, aber dies würde erstellen enge Kopplung zwischen den Klassen die wird nicht empfohlen.

Silverlight-Navigationsbereich erweitern

Silverlight-Navigation-Anwendung ist eine Visual Studio-Vorlage, mit der Sie schnell erstellen, Anwendungen, die Navigation mit einen Rahmen, der als Host des Inhalts. Der große Vorteil Frames ist, dass Sie die Schaltflächen zurück und weiter Ihres Browsers integriert werden und tief verknüpfen unterstützen. Sehen Sie sich die folgenden:

<navigation:Frame x:Name="ContentFrame" 
  Style="{StaticResource ContentFrameStyle}" 
  Source="Customers" 
  NavigationFailed="OnNavigationFailed">
  <i:Interaction.Behaviors>
    <fw:CompositionNavigationBehavior />
  </i:Interaction.Behaviors>
</navigation:Frame>

Hierbei handelt es sich um einen normalen Rahmen, der durch Navigieren zu Kunden beginnt. Wie Sie sehen können, enthält in diesem Rahmen einen UriMapper keine (wo Sie Kunden mit einer XAML-Datei, wie z. B. /Views/Customers.aspx verknüpfen konnte). Das einzige, was, das es enthält, ist mein benutzerdefiniertes Verhalten CompositionNavigationBehavior. Ein Verhalten (aus der Assembly System.Windows.Interactivity) ermöglicht es Ihnen, vorhandene Steuerelemente, z. B. ein Frame in diesem Fall zu erweitern.

Abbildung 1 veranschaulicht das Verhalten. Nehmen Sie einen Einblick in die Funktionsweise dieser CompositionNavigationBehavior Let’s. Das erste, was, das Sie sehen können, ist, dass das Verhalten einer CompositionContainer und eine CompositionNavigationLoader (mehr dazu später) Attribute für die importieren möchte. Der Konstruktor wird dann importieren, der mithilfe der SatisfyImports-Methode für das CompositionInitializer erzwungen. Beachten Sie, dass nur diese Methode sollte Wenn Sie eine andere Wahl, als es den Code tatsächlich um MEF verkoppelt.

Abbildung 1 CompositionNavigationBehavior

public class CompositionNavigationBehavior : Behavior<Frame> {
  private bool processed;
  [Import]
  public CompositionContainer Container { 
    get; set; 
  }

  [Import]
  public CompositionNavigationContentLoader Loader { 
    get; set; 
  }

  public CompositionNavigationBehavior() {
    if (!DesignerProperties.IsInDesignTool)
      CompositionInitializer.SatisfyImports(this);
  }

  protected override void OnAttached() {
    base.OnAttached();
    if (!processed) {
       this.RegisterNavigationService();
       this.SetContentLoader();
       processed = true;
    }
  }

  private void RegisterNavigationService() {
    var frame = AssociatedObject;
    var svc = new NavigationService(frame);
    Container.ComposeExportedValue<INavigationService>(svc);
  }

  private void SetContentLoader() {
    var frame = AssociatedObject;
    frame.ContentLoader = Loader;
    frame.JournalOwnership = JournalOwnership.Automatic;
  }
}

Wenn das Frame-Objekt zugeordnet ist, wird eine NavigationService erstellt und um den Rahmen herum umbrochen. ComposeExportedValue verwendet wird, ist die Instanz dieses Wrappers im Container registriert.

Bei der Erstellung des Containers wurde die Instanz dieses Containers auch selbst registriert. Dies hat zur Folge, erhalten ein Import von CompositionContainer immer das gleiche Objekt Sie;Dies ist der Grund, warum ich ComposeExportedValue in der Startup-Ereignis des App-Klasse verwendet. Jetzt die CompositionNavigationBehavior bittet um einen CompositionContainer mithilfe des Import-Attributs und erhalten Sie nach SatisfyImports ausgeführt wird.

Beim Registrieren der Instanz des INavigationService geschieht dasselbe. Es ist jetzt möglich von überall in der Anwendung, eine INavigationService abzufragen (die einen Rahmen umfließt). Ohne Ihre ViewModels in einen Positionsrahmen zu koppeln, erhalten Sie Zugriff auf die folgenden:

public interface INavigationService {
  void Navigate(string path);
  void Navigate(string path, params object[] args);
}

Jetzt let’s nehmen an, Sie haben eine ViewModel aller Kunden angezeigt und dieses ViewModel sollte in der Lage, einen bestimmten Kunden zu öffnen. Dies kann erreicht werden, mithilfe des folgenden Codes:

[Import]
public INavigationService NavigationService { 
  get; set; 
}

private void OnOpenCustomer() {
  NavigationService.Navigate(
    "Customer/{0}", SelectedCustomer.Id);
}

Doch bevor im Voraus springen, SetContentLoader-Methode in der CompositionNavigationBehavior let’s besprechen. Es ändert die ContentLoader von Rahmen. Dies ist ein perfektes Beispiel dafür die Unterstützung für Erweiterbarkeit in Silverlight. Wirklich etwas zum Anzeigen im Rahmen bereitstellen, können Sie Ihre eigenen ContentLoader (die INavigationContentLoader-Schnittstelle implementiert) bereitstellen.

Nun, da Sie sehen können, wie die Dinge starten fallen an, das folgende Thema – MEF erweitern – wird klar werden.

Zurück zum Erweitern von MEF

Das Ziel ist es, dass Sie zu einem bestimmten Pfad navigieren können (aus der ViewModel oder in die Adresszeile des Browsers zulässig) und die CompositionNavigationLoader den Rest erledigt. Es sollte analysiert den URI, sucht nach einer übereinstimmenden ViewModel und eine entsprechende Ansicht und zu kombinieren.

Normalerweise würden Sie etwa Folgendes schreiben:

[Export(typeof(IMainViewModel))]
public class MainViewModel

In diesem Fall wäre es interessant, verwenden Sie das Export-Attribut mit einigen zusätzlichen Konfiguration als Metadaten bezeichnet sein. Abbildung 2 zeigt ein Beispiel für ein Metadatenattribut.

Abbildung 2 erstellen die ViewModelExportAttribute

[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class ViewModelExportAttribute : 
  ExportAttribute, IViewModelMetadata {
..public Type ViewModelContract { get; set; }
  public string NavigationPath { get; set; }
  public string Key { get; set; }  

  public ViewModelExportAttribute(Type viewModelContract, 
    string navigationPath) : base(typeof(IViewModel)) {

    this.NavigationPath = navigationPath;
    this.ViewModelContract = viewModelContract;
    if (NavigationPath != null && 
      NavigationPath.Contains("/")) {
      // Split the path to get the arguments.
var split = NavigationPath.Split(new char[] { '/' }, 
        StringSplitOptions.RemoveEmptyEntries);
      // Get the key.
Key = split[0];
    }
    else {
      // No arguments, use the whole key.
Key = NavigationPath;
    }
  }
}

Dieses Attribut macht etwas besonderes nicht. Zusätzlich zu der Schnittstelle ViewModel ermöglicht es Sie definieren einen Navigationspfad z. B. Customer / {ID}. Anschließend wird dieser Pfad unter Verwendung von Kunden als Schlüssel und {ID} als eines der Argumente verarbeitet werden. Hier ist ein Beispiel für die Verwendung dieses Attributs:

[ViewModelExport(typeof(ICustomerDetailViewModel), 
  "Customer/{id}")]
public class CustomerDetailViewModel 
  : ICustomerDetailViewModel

Bevor Sie fortfahren, sind einige wichtige Punkte zu beachten. Zunächst sollte das Attribut [MetadataAttribute] ordnungsgemäß funktionieren erhalten. Zweitens sollte das Attribut implementieren Sie eine Schnittstelle mit den Werten als Metadaten verfügbar gemacht werden soll. Und schließlich den Konstruktor des Attributs — einen Typ an den Basiskonstruktor übergeben. Die Klasse, die mit diesem Attribut ergänzt ist wird mit diesem Typ verfügbar gemacht werden. Im Fall von meinem Beispiel wäre dies IViewModel.

Das ist für den Export der ViewModels. Wenn Sie an einer Stelle importieren möchten, sollten Sie etwa Folgendes schreiben:

[ImportMany(typeof(IViewModel))]
public List<Lazy<IViewModel, IViewModelMetadata>> ViewModels { 
  get; 
  set; 
}

Dadurch erhalten Sie eine Liste mit allen ViewModels mit Ihren jeweiligen Metadaten, die es Ihnen ermöglicht, durchlaufen die Liste, und wählen Sie vielleicht nur benötigte von Interesse für Sie (auf der Grundlage von Metadaten) exportiert. In der Tat wird Lazy Objekt sicherstellen, dass nur diejenigen interessant tatsächlich instanziiert werden.

Die Ansicht ist etwas Ähnliches erforderlich:

[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class ViewExportAttribute : 
  ExportAttribute, IViewMetadata {

  public Type ViewModelContract { get; set; }
  public ViewExportAttribute() : base(typeof(IView)) {
  }
}

Es gibt keine besonderen in diesem Beispiel entweder. Dieses Attribut können Sie den Vertrag der ViewModel festlegen, mit denen die Ansicht verknüpft werden soll.

Hier ist ein Beispiel für AboutView:

[ViewExport(ViewModelContract = typeof(IAboutViewModel))]
public partial class AboutView : Page, IView {
  public AboutView() {
    InitializeComponent();
  }
}

Eine benutzerdefinierte INavigationContentLoader

Nun, da die Gesamtarchitektur eingerichtet wurde, let’s betrachten steuern, welche geladen wird, wenn ein Benutzer navigiert. Ein Ladeprogramm für benutzerdefinierten Inhalt erstellen möchten, muss die folgende Schnittstelle implementiert werden:

public interface INavigationContentLoader {
  IAsyncResult BeginLoad(Uri targetUri, Uri currentUri, 
    AsyncCallback userCallback, object asyncState);
  void CancelLoad(IAsyncResult asyncResult);
  bool CanLoad(Uri targetUri, Uri currentUri);
  LoadResult EndLoad(IAsyncResult asyncResult);
}

Der wichtigste Teil der Benutzeroberfläche ist die BeginLoad-Methode, da diese Methode zurückgeben soll ein AsyncResult mit dem Artikel, der in dem Frame angezeigt wird. Abbildung 3 zeigt die Implementierung von benutzerdefinierten INavigationContentLoader.

Abbildung 3 benutzerdefinierte 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); 
  }
}

Wie Sie sehen können, sehr viel passiert in dieser Klasse, aber es ist wirklich ganz einfach. Als Erstes fällt auf ist das Export-Attribut. Dies ist erforderlich, damit diese Klasse in der CompositionNavigationBehavior importiert werden.

Die wichtigsten Teile dieser Klasse sind die Eigenschaften ViewExports und ViewModelExports. Diese Enumerationen werden alle Exporte für die Ansichten und der ViewModels, einschließlich der zugehörigen Metadaten enthalten. Anstatt ein Lazy-Objekt verwende ich eine ExportFactory. Dies ist ein großer Unterschied! Beide Klassen werden nur das Objekt bei Bedarf instanziiert, aber der Unterschied besteht darin, dass mit der Lazy-Klasse nur eine einzige Instanz des Objekts erstellen können. Die ExportFactory (benannt nach dem Muster Factory) ist eine Klasse, mit der Sie eine neue Instanz des Typs eines Objekts anfordern, sobald wie es Ihrer Meinung nach.

Schließlich ist die BeginLoad-Methode. Dies geschieht, in denen die magische. Dies ist die Methode, die den Frame mit dem Inhalt angezeigt, nachdem Sie an einen bestimmten URI bereitstellen.

Erstellen und Aufbereiten von Objekten

Let’s sagen Sie anweisen, den Rahmen, um Kunden zu navigieren. Das ist, was Sie in das Argument TargetUri der BeginLoad-Methode finden. Sobald dies erhalten Sie arbeiten.

Führen Sie als Erstes ist die richtige ViewModel finden. Die ViewModelExports-Eigenschaft ist eine Enumeration, die Exporte mit deren Metadaten enthält. Mit einen Lambda-Ausdruck finden Sie den richtigen ViewModel basierend auf den Schlüssel. Beachten Sie Folgendes:

[ViewModelExport(typeof(ICustomersViewModel), "Customers")]
public class CustomersViewModel : 
  ContosoViewModelBase, ICustomersViewModel

Genommen Sie an, gut, Sie an Kunden navigieren. Die richtige ViewModel finden Sie dann der folgende Code:

var viewModelMapping = ViewModelExports.FirstOrDefault(o => o.Metadata.Key.Equals("Customers", 
  StringComparison.OrdinalIgnoreCase));

Sobald die ExportFactory gefunden wird, sollte das gleiche für die Ansicht erfolgen. Allerdings suchen anstelle der Navigationstaste gesucht, Sie die ViewModelContract gemäß der Definition in der ViewModelExportAttribute und die ViewModelAttribute:

[ViewExport(ViewModelContract = typeof(IAboutViewModel))
public partial class AboutView : Page

Wenn beide ExportFactories gefunden haben, ist der Festplatte Teil über. Jetzt können mit CreateExport-Methode eine neue Instanz der Ansicht und dem ViewModel erstellen:

var viewFactory = viewMapping.CreateExport(); 
var view = viewFactory.Value as Control; 
var viewModelFactory = viewModelMapping.CreateExport(); 
var viewModel = viewModelFactory.Value as IViewModel;

Nachdem sowohl die Ansicht als auch die ViewModel erstellt wurden, wird die ViewModel in den DataContext des der Ansicht, und starten die erforderlichen Datenbindungen gespeichert. Und die OnLoaded-Methode der ViewModel wird aufgerufen, um die ViewModel zu benachrichtigen, die die Schwerarbeit ausgeführt wurde, und außerdem, dass alle Importe – falls vorhanden – importiert wurden.

Wenn Sie das Importieren und ImportMany-Attribut sollte nicht den letzten Schritt nicht unterschätzt werden. In vielen Fällen möchten Sie etwas tun, beim Erstellen einer ViewModel, jedoch nur, wenn alles richtig geladen wurde. Wenn Sie eine ImportingConstructor Sie definitiv wissen, wenn alle Imports importiert wurden (, würde sein, wenn der Konstruktor aufgerufen wird). Aber bei der Arbeit mit der Import/ImportMany Attribute sollten Sie beginnen, Schreiben von Code in Ihre Eigenschaften in Flags festgelegt werden, um festzustellen, wann alle Eigenschaften importiert wurden.

In diesem Fall löst die Methode OnLoaded dieses Problem für Sie.

Übergeben von Argumenten an die ViewModel

Sehen Sie sich die IViewModel-Schnittstelle, und achten Sie auf die OnNavigated-Methode:

public interface IViewModel {
  void OnLoaded();
  void OnNavigated(NavigationArguments args);
  string GetTitle();
}

Beim Navigieren zu Kunden/1 z. B. dieser Pfad wird analysiert, und die Argumente in der NavigationArguments-Klasse (Dies ist nur ein Wörterbuch mit zusätzlichen Methoden wie GetInt, GetString usw.) kombiniert werden. Da es obligatorisch ist, dass jede ViewModel IViewModel-Schnittstelle implementiert, ist es möglich, die OnNavigated-Methode aufrufen, nachdem Sie die ViewModel:

// Get navigation values.
var values = viewModelMapping.Metadata.GetArgumentValues(targetUri); viewModel.OnNavigated(values);

Wenn die CustomersViewModel ein CustomerDetailViewModel öffnen möchte, geschieht Folgendes:

NavigationService.Navigate("Customer/{0}", SelectedCustomer.Id);

Diese Argumente werden dann Eintreffen in der CustomerDetailViewModel und können verwendet werden, z. B. an der DataService übergeben:

public override void OnNavigated(NavigationArguments args) {
  var id = args.GetInt("Id");
  if (id.HasValue) {
    Customer = DataService.GetCustomerById(id.Value);
  }
}

Um die Argumente zu finden, habe ich eine Klasse mit zwei Erweiterungsmethoden, die einige Arbeit, die basierend auf den Informationen in den Metadaten ViewModel (siehe Abbildung 4 ). Dies beweist erneut, dass das Metadaten Konzept MEF nützlich ist.

image: Extension Methods for Navigation Arguments

Abbildung 4 Erweiterungsmethoden für Navigationsbereich-Argumente

Abschließenden Aufgaben

Ist die Anzeigen einer Seite oder einem ChildWindow, wird der Titel des Steuerelements auch aus dem Objekt IViewModel extrahiert. Dadurch können Sie die Titel der Seiten und basierend auf der aktuellen Kunden ChildWindows dynamisch festgelegt wird, wie in der Abbildung 5 .

image: Setting a Custom Window Title

Abbildung 5 Festlegen eines benutzerdefinierten Fenstertitel

Nachdem Sie alle diese sehr kleine Dinge ist einem letzten Schritt. Wenn die Ansicht eine ChildWindow im Fenster angezeigt werden soll. Aber wenn die ViewModel IClosableViewModel implementiert, sollte das CloseView-Ereignis dieses ViewModel mit der Close-Methode der ChildWindow verknüpft werden.

Die IClosableViewModel-Schnittstelle ist einfach:

public interface IClosableViewModel : IViewModel {
  event EventHandler CloseView;
}

Verarbeitung der ChildWindow ist einfach. Wenn die ViewModel CloseView-Ereignis auslöst, wird die Close-Methode der ChildWindow aufgerufen. Dadurch werden die ViewModel indirekt zur Ansicht zu verbinden:

// 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();

Wenn die Ansicht eine ChildWindow ist, sollte dann es einfach in das IAsyncResult verfügbar.Dies wird im Rahmen die Ansicht angezeigt.

Vorhanden.Sie haben jetzt den gesamten Prozess der Aufbau von der Ansicht und ViewModel gesehen.

Verwenden den Beispielcode

Der Codedownload für diesen Artikel enthält eine MVVM Anwendung MEF mit dieser Art von benutzerdefinierte Navigation.Die Projektmappe enthält die folgenden Beispiele:

  • Navigieren zu einem regulären UserControl
  • Navigieren zu einem regulären UserControl, durch die Übergabe von Argumenten (.../#Employee/DiMattia)
  • Navigieren zu einem ChildWindow, durch die Übergabe von Argumenten (.../#Customer/1)
  • Importe von INavigationService, die IDataService...
  • Beispiele für die Konfiguration der ViewExport und ViewModelExport

Dieser Artikel soll einen Überblick über die Funktionsweise des Beispiels bereitgestellt haben.Experimentieren Sie für ein besseres Verständnis mit den Code, und passen Sie es für Ihre eigenen Anwendungen.Sie werden sehen, wie leistungsfähig und flexibel MEF kann.

Sandrino Di Mattia is a software engineer at RealDolmen and has a passion for everything that is Microsoft. Er auch Benutzergruppen beteiligt und schreibt in seinem Blog unter blog.sandrinodimattia.net-Artikeln.

Dank an die folgenden technischen Experten für die Überprüfung der in diesem Artikel: Glenn Block und Daniel Plaisted