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.