Come si imposta un ViewModel su una finestra in XAML utilizzando la proprietà DataContext?


96

La domanda dice praticamente tutto.

Ho una finestra e ho provato a impostare DataContext utilizzando lo spazio dei nomi completo su ViewModel, ma sembra che stia facendo qualcosa di sbagliato.

<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">

Risposte:


112

Oltre alla soluzione fornita da altre persone (che è buona e corretta), esiste un modo per specificare ViewModel in XAML, ma separare comunque il ViewModel specifico dalla View. Separarli è utile quando si desidera scrivere casi di test isolati.

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}"
    />

Oh wow ... grazie. L'ho già segnato come risposta, ma la tua aggiunta è molto apprezzata. Lo userò.
Nicholas

@Nicholas: l'altra risposta è perfetta per la domanda, quindi sono d'accordo con la tua decisione
Merlyn Morgan-Graham

8
Tieni presente che questo approccio utilizza la stessa istanza ViewModel per ogni istanza di MainWindow. Va bene se la finestra è a istanza singola come implica questo caso, ma non se stai mostrando più istanze della finestra come nel caso di un'applicazione MDI o a schede.
Josh

1
In realtà la risposta di Josh è migliore in quanto ti dà l'indipendenza dai tipi su DataContext. Quindi puoi collegarti direttamente a DataContext senza preoccuparti di digitare un nome / percorso di proprietà.
Josh M.

149

Prova questo invece.

<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>

3
Mi piace di più questa opzione. Sembra più pulito se la VM viene utilizzata solo per MainWindow.
Andrew Grothe,

13
C'è un modo per impostare il contesto dei dati utilizzando un attributo Windowsull'elemento, come DataContext="VM:MainWindowViewModel"?
Oliver

Questo è il modo corretto!
JavierIEH

Non capisco completamente perché un modo è migliore dell'altro. Inoltre, non vedo completamente la differenza in nessuno di questi modi rispetto a come ho visto alcune persone usare "Dynamic Resource". Cos'è questo?
Travis Tubbs

1
@Oliver dovresti implementarlo MarkupExtension, non l' hai mai fatto sulle VM, ma potresti farlo con i convertitori per assicurarti che sia presente solo un'istanza del convertitore e chiamarla direttamente da xaml con ="{converters:SomethingConverter}", implicando xmlns:converterspunti nello spazio dei nomi del convertitore. 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

È necessario creare un'istanza di MainViewModel e impostarlo come datacontext. Nella tua dichiarazione lo consideri semplicemente come un valore stringa.

     <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>

Grazie, ho pensato che lo stesse facendo.
Nicholas

3

Potresti provare Catel . Ti consente di definire una classe DataWindow (invece di Window) e quella classe crea automaticamente il modello di visualizzazione per te. In questo modo, puoi utilizzare la dichiarazione del ViewModel come hai fatto nel tuo post originale e il modello di visualizzazione verrà comunque creato e impostato come DataContext.

Vedi questo articolo per un esempio.


1

C'è anche questo modo per specificare il viewmodel:

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>

Tutte le soluzioni proposte in precedenza richiedono che MainViewModeldebba avere un costruttore senza parametri.

Microsoft ha l'impressione che i sistemi possano essere costruiti utilizzando costruttori senza parametri. Se anche tu hai questa impressione, vai avanti e utilizza alcune delle altre soluzioni.

Per coloro che sanno che i costruttori devono avere parametri, e quindi la creazione di istanze di oggetti non può essere lasciata nelle mani di quadri magici, il modo corretto di specificare il viewmodel di quello che ho mostrato sopra.

</Rant>

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.