web-dev-qa-db-fra.com

Comment spécifier le type DataContext (ViewModel) pour obtenir la vérification des liaisons au moment du design dans l'éditeur XAML sans créer un objet ViewModel?

Je peux spécifier DataContext comme ceci:

<Window ... >
    <Window.DataContext>
        <MainViewModel />
    </Window.DataContext>
    ...
</Window>

Et dans ce cas, WPF créera un objet de type MainViewModel et l'affectera à la propriété DataContext de la fenêtre (cela se produit dans la méthode InitializeComponent() de Window).

Mais que faire si mon ViewModel n'a pas de constructeur par défaut. Ou si je veux initialiser ViewModel et l'assigner à DataContext après l'exécution de Window.InitializeComponent() (à l'intérieur du constructeur de Window ou à partir du même code qui instancie la fenêtre) - dans ce cas, WPF crée un ViewModel (à l'intérieur de la fonction InitializeComponent()), l'assigne au DataContext de la fenêtre, puis je l'écrase avec une autre instance de ViewModel (je m'inquiète de l'instanciation inutile des objets ici).

Je voudrais pouvoir spécifier juste un type de ViewModel, donc je recevrais un avertissement au moment du design si j'épelle mal un nom de propriété dans {Binding} (ou après avoir renommé la propriété), ou je pourrais aller à Déclaration en cliquant (en XAML) sur un nom de propriété dans {Binding PropertyName}.

Merci pour votre temps inestimable.

41
WpfNewbie

C'est la partie délicate si vous faites le MVVM à faire soi-même.

Vos options, essentiellement:

tiliser l'injection de dépendance

Vous pouvez injecter le ViewModel dans le constructeur de votre Page/Window et l'affecter à l'intérieur.

Cela a cependant quelques inconvénients.

  • plus difficile à utiliser les modèles de vue au moment de la conception
  • Les vues ne peuvent plus être instanciées à partir de XAML

ViewModel First avec le service de navigation

Vous résolvez vos ViewModels et effectuez toute votre navigation via un service de navigation. Dans vos ViewModels, vous passez un INavigationService. Vous pouvez naviguer vers une vue en utilisant le type ViewModel. À l'intérieur, il instancie le ViewModel via l'injection de dépendances, puis instancie la vue (en fonction des conventions de dénomination ou via la configuration DI)

C'est un peu mieux, mais cela ne vous permettra toujours pas d'instancier les vues dans XAML. Le gros plus est qu'il permet de passer facilement des paramètres au ViewModel (en faisant en sorte que les ViewModels implémentent la propriété INavigationAware avec la méthode NavigatedTo, qui est appelée après l'instanciation et en passant le paramètre à)

ViewModelLocator/Propriété attachée/Comportement

Avec celle-ci, vous créeriez une propriété attachée, que vous définissez soit sur true (c.-à-d. Autowire) ou sur un type ViewModel (pour avoir plus de contrôle sur le ViewModel instancié) et la recherche et la résolution du ViewModel et l'attribution il.

Il donne essentiellement tous les avantages ci-dessus ainsi que la vue d'instanciation.

Le dernier est essentiellement ce que fait le framework MVVM de Microsoft "Prism" (service de navigation navigationService.Navigate("MyPage", myParameterForViewModel), instanciation DataContext et affectation à partir de XAML via le câblage automatique (dans XAML: prism:ViewModelLocator.AutoWireViewModel="True").

Cela étant dit, il est préférable d'utiliser un framework MVVM mûri qui effectue ces parties de votre câblage (même si vous décidez de ne pas utiliser les classes de base telles que BindableBase ou tout autre nom dans ce framework).

En ce qui concerne ViewModel au moment de la conception/auto-complétion pour ViewModels:

Pour ce faire, vous pouvez utiliser les attributs de conception de Blend. Vous devez d'abord ajouter les références d'assemblage de mélange. Ensuite, vous pouvez ajouter xmlns:d="http://schemas.Microsoft.com/expression/blend/2008" espace de noms dans votre page/vue.

Ensuite, vous pouvez le lier à votre page via d:DataContext="{d:DesignInstance my:DesignTimeViewModel, IsDesignTimeCreatable=True}. Remarquez le d: avant le DataContext, c'est important. Ce DataContext ne sera utilisé que dans le concepteur (concepteur Visual Studio XAML ou dans Blend). C'est pour éviter d'interférer avec le DataContext normal (sans le préfixe).

Exemple:

<Window x:Class="WpfApplication1.Window2"
        xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.Microsoft.com/expression/blend/2008"
        xmlns:myApp="clr-namespace:WpfApplication1"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        d:DataContext="{d:DesignInstance myApp:Window2ViewModel, IsDesignTimeCreatable=True}">
    <Grid>
        <TextBlock Text ="{Binding Test}"/>
    </Grid>
</Window>

Si vous utilisez des interfaces pour vos ViewModels, il est assez rapide de créer l'instance de conception, en demandant simplement à Visual Studio d'implémenter toutes les propriétés d'interface et de lui donner des valeurs par défaut (pour la propriété, vous avez donc des exemples de données dans votre ViewModel pour vérifier que les liaisons fonctionnent correctement) .

Cela vous oblige à créer des ViewModels au moment du design et vos ViewModels réels, ce qui n'est pas aussi mauvais qu'il y paraît. Cela donne à votre concepteur d'interface utilisateur la possibilité de travailler avec lui, même si le vrai ViewModel n'est pas encore terminé/implémenté.

43
Tseng