105 votes

Comment définir un ViewModel sur une fenêtre dans XAML en utilisant la propriété DataContext ?

La question dit à peu près tout.

J'ai une fenêtre, et j'ai essayé de définir le DataContext en utilisant l'espace de noms complet pour le ViewModel, mais il semble que je fasse quelque chose de mal.

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

0 votes

Pour faire suite à Mike Nakis, j'ai essayé de créer le ViewModel manuellement et de m'abonner à des événements dans celui-ci, mais je me suis aperçu que le framework créait un autre ViewModel. Par conséquent, le ViewModel auquel j'étais abonné n'était pas celui qui était attaché à la vue.

0 votes

Est-ce que ça veut dire qu'en plus d'instancier le modèle de vue vous-même, vous étiez également spécifier le type du modèle de vue d'une autre manière ? Un autre avantage des modèles de vue nécessitant des paramètres de construction est que le framework ne peut pas les instancier, ou bien il doit passer des valeurs par défaut pour ces paramètres, auquel cas vous pouvez facilement détecter l'instanciation par le framework.

0 votes

Le concepteur XAML pourrait aussi avoir besoin de pouvoir instancier des modèles de vue, mais ce concepteur n'a jamais été d'une quelconque utilité pour moi (il ne fait que causer des problèmes), donc je ne l'utilise pas, donc je ne me soucie pas personnellement de ce cas d'utilisation.

159voto

Josh Points 38617

Essayez plutôt ceci.

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

C'est l'option que je préfère. Elle semble plus propre si la VM n'est utilisée que pour la MainWindow.

13 votes

Existe-t-il un moyen de définir le contexte des données à l'aide d'un attribut de l'attribut Window comme DataContext="VM:MainWindowViewModel" ?

0 votes

C'est la bonne méthode !

122voto

Merlyn Morgan-Graham Points 31815

En plus de la solution proposée par d'autres personnes (qui est bonne et correcte), il existe un moyen de spécifier le ViewModel dans XAML, tout en séparant le ViewModel spécifique de la vue. Les séparer est utile lorsque vous voulez écrire des cas de test isolés.

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

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

0 votes

Oh wow... merci. Je l'ai déjà marqué comme répondu, mais votre ajout est très apprécié. Je l'utiliserai.

0 votes

@Nicholas : L'autre réponse est parfaite pour la question, donc je suis d'accord avec votre décision.

9 votes

Sachez simplement que cette approche utilise la même instance de ViewModel pour chaque instance de MainWindow. Cela convient si la fenêtre est à une seule instance, comme dans ce cas, mais pas si vous affichez plusieurs instances de la fenêtre, comme dans le cas d'une application MDI ou à onglets.

12voto

Jobi Joy Points 20883

Vous devez instancier le MainViewModel et le définir comme contexte de données. Dans votre déclaration, il est simplement considéré comme une valeur de type string.

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

0 votes

Merci, je me doutais que ça faisait ça.

6voto

Mike Nakis Points 7259

Il y a aussi cette façon de spécifier le modèle de vue :

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>

Toutes les solutions proposées précédemment exigent que MainViewModel doit avoir un constructeur sans paramètre.

Microsoft a l'impression que les systèmes peuvent être construits à l'aide de constructeurs sans paramètres. Si vous avez également cette impression, allez-y et utilisez d'autres solutions.

Pour ceux qui savent que les constructeurs doivent avoir des paramètres et que, par conséquent, l'instanciation des objets ne peut être laissée entre les mains de frameworks magiques, la manière correcte de spécifier le viewmodel est celle que j'ai montrée ci-dessus.

</Rant>

0 votes

Et si j'ai un <UserControl> avec une MainView et une MainViewModel - ici, je n'ai pas de OnStartup événement, c'est en fait ce que je suis en train de chercher en ce moment...

0 votes

@PandaWood Je ne vous suis pas. Est-ce que votre UserControl (appelons-le MyUserControl ) le visuel racine de l'application, ou vit-il dans une fenêtre ? Dans les deux cas, MyUserControl est une vue, donc il n'est pas clair comment cette autre MainView s'intègre dans le tableau.

0 votes

Si MyUserControl est censé vivre à l'intérieur d'une autre vue (disons, à l'intérieur de la vue MyMainView ), alors MyMainViewModel aurait un MyUserControlViewModel donc dans MainWindowView tu dirais juste <MyUserControl DataContext="{Binding MyUserControlViewModel}" /> .

3voto

Geert van Horrik Points 1809

Vous pouvez essayer Catel . Il vous permet de définir une classe DataWindow (au lieu de Window), et cette classe crée automatiquement le modèle de vue pour vous. De cette façon, vous pouvez utiliser la déclaration du ViewModel comme vous l'avez fait dans votre message original, et le modèle de vue sera toujours créé et défini comme DataContext.

Ver cet article pour un exemple.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X