Wie setze ich ein ViewModel in einem Fenster in XAML mithilfe der DataContext-Eigenschaft?

95

Die Frage sagt so ziemlich alles.

Ich habe ein Fenster und habe versucht, den DataContext unter Verwendung des vollständigen Namespace für das ViewModel festzulegen, aber ich scheine etwas falsch zu machen.

<Window x:Class="BuildAssistantUI.BuildAssistantWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    DataContext="BuildAssistantUI.ViewModels.MainViewModel">
Nikolaus
quelle

Antworten:

112

Zusätzlich zu der von anderen Personen bereitgestellten Lösung (die gut und korrekt ist) gibt es eine Möglichkeit, das ViewModel in XAML anzugeben und dennoch das spezifische ViewModel von der Ansicht zu trennen. Das Trennen ist nützlich, wenn Sie isolierte Testfälle schreiben möchten.

In App.xaml:

<Application
    x:Class="BuildAssistantUI.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:BuildAssistantUI.ViewModels"
    StartupUri="MainWindow.xaml"
    >
    <Application.Resources>
        <local:MainViewModel x:Key="MainViewModel" />
    </Application.Resources>
</Application>

In MainWindow.xaml:

<Window x:Class="BuildAssistantUI.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    DataContext="{StaticResource MainViewModel}"
    />
Merlyn Morgan-Graham
quelle
Oh wow ... danke. Ich habe dies bereits als beantwortet markiert, aber Ihre Hinzufügung wird sehr geschätzt. Ich werde es benutzen.
Nicholas
@Nicholas: Die andere Antwort ist perfekt für die Frage, also stimme ich Ihrer Entscheidung zu
Merlyn Morgan-Graham
8
Beachten Sie jedoch, dass dieser Ansatz für jede Instanz von MainWindow dieselbe ViewModel-Instanz verwendet. Dies ist in Ordnung, wenn das Fenster eine Einzelinstanz ist, wie in diesem Fall impliziert, aber nicht, wenn Sie mehrere Instanzen des Fensters anzeigen, z. B. im Fall einer MDI- oder Registerkartenanwendung.
Josh
1
Eigentlich ist Joshs Antwort besser, da sie Ihnen Typensicherheit im DataContext bietet. Sie können also direkt an den DataContext binden, ohne sich Gedanken über die Eingabe eines Eigenschaftsnamens / -pfads machen zu müssen.
Josh M.
149

Versuchen Sie dies stattdessen.

<Window x:Class="BuildAssistantUI.BuildAssistantWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:VM="clr-namespace:BuildAssistantUI.ViewModels">
    <Window.DataContext>
        <VM:MainViewModel />
    </Window.DataContext>
</Window>
Josh
quelle
3
Diese Option gefällt mir am besten. Scheint sauberer, wenn die VM nur für das MainWindow verwendet wird.
Andrew Grothe
13
Gibt es eine Möglichkeit, den Datenkontext mithilfe eines Attributs für das WindowElement festzulegen, z DataContext="VM:MainWindowViewModel".
Oliver
Das ist der richtige Weg!
JavierIEH
Ich verstehe nicht ganz, warum ein Weg besser ist als der andere. Außerdem sehe ich den Unterschied auf keine dieser Arten im Vergleich zu der Art und Weise, wie einige Leute "Dynamic Resource" verwenden. Was ist das?
Travis Tubbs
1
@Oliver müssten Sie implementieren MarkupExtension, haben es nie auf VMs gemacht, aber Sie könnten es mit Konvertern machen, um sicherzustellen, dass nur eine Instanz des Konverters vorhanden ist, und es direkt von xaml mit aufrufen ="{converters:SomethingConverter}", was xmlns:convertersPunkte im Konverter-Namespace impliziert . public abstract class BaseValueConverter<T> : MarkupExtension, IValueConverter where T : class, new() { private static T _converter; public override object ProvideValue(IServiceProvider serviceProvider) { return _converter ?? (_converter = new T()); } }
Whazz
11

Sie müssen das MainViewModel instanziieren und als Datenkontext festlegen. In Ihrer Anweisung wird es nur als Zeichenfolgenwert betrachtet.

     <Window x:Class="BuildAssistantUI.BuildAssistantWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:BuildAssistantUI.ViewModels">
      <Window.DataContext>
        <local:MainViewModel/>
      </Window.DataContext>
Jobi Joy
quelle
Danke, ich dachte, dass es das tut.
Nicholas
3

Vielleicht möchten Sie Catel ausprobieren . Sie können eine DataWindow-Klasse (anstelle von Window) definieren, und diese Klasse erstellt automatisch das Ansichtsmodell für Sie. Auf diese Weise können Sie die Deklaration des ViewModel wie in Ihrem ursprünglichen Beitrag verwenden, und das Ansichtsmodell wird weiterhin erstellt und als DataContext festgelegt.

In diesem Artikel finden Sie ein Beispiel.

Geert van Horrik
quelle
0

Es gibt auch folgende Möglichkeit, das Ansichtsmodell anzugeben:

using Wpf = System.Windows;

public partial class App : Wpf.Application //your skeleton app already has this.
{
    protected override void OnStartup( Wpf.StartupEventArgs e ) //you need to add this.
    {
        base.OnStartup( e );
        MainWindow = new MainView();
        MainWindow.DataContext = new MainViewModel( e.Args );
        MainWindow.Show();
    }
}

<Rant>

Alle zuvor vorgeschlagenen Lösungen erfordern MainViewModeleinen parameterlosen Konstruktor.

Microsoft hat den Eindruck, dass Systeme mit parameterlosen Konstruktoren erstellt werden können. Wenn Sie auch unter diesem Eindruck stehen, verwenden Sie einige der anderen Lösungen.

Für diejenigen, die wissen, dass Konstruktoren Parameter haben müssen und daher die Instanziierung von Objekten nicht in den Händen magischer Frameworks liegen kann, ist dies die richtige Methode, um das Ansichtsmodell des oben gezeigten anzugeben.

</ Rant>

Mike Nakis
quelle