Question

Ma question générique est comme l'indique le titre, est-il préférable de charger les données lors de la construction ou ViewModel ensuite par un événement Loaded manipulation?

Je devine que la réponse est après la construction par une gestion de l'événement Loaded, mais je me demande comment cela est plus proprement coordonnée entre ViewModel et afficher?

est ici plus de détails sur ma situation et le problème particulier, je suis en train de résoudre:

J'utilise le cadre clair MVVM ainsi que l'unité de DI. J'ai des vues imbriquées, chacune liée à un ViewModel correspondant. Les ViewModels sont liés à chaque contrôle de DataContext de racine Voir par l'idée que Laurent Bugnion ViewModelLocator a mis en lumière MVVM. Cela permet de trouver ViewModels via une ressource statique et pour contrôler la durée de vie ViewModels par un cadre d'injection de dépendance, dans ce cas, l'unité. Il permet également d'Expression Blend pour voir tout ce qui concerne ViewModels et comment les lier.

De toute façon, j'ai une vue parent qui a un databound ComboBox à une ObservableCollection dans son ViewModel. est également lié le SelectedItem du ComboBox (dans les deux sens) à une propriété sur le ViewModel. Lorsque la sélection des changements ComboBox, est de déclencher des mises à jour dans d'autres points de vue et subviews. Actuellement, je suis en train d'accomplir ce via le système de messagerie qui se trouve dans MVVM Lumière. Tout cela est vraiment génial de travailler et comme prévu lorsque vous choisissez différents éléments dans la liste déroulante.

Cependant, le ViewModel obtient ses données au cours de la construction par une série d'initialisation appels de méthode. Cela semble être seulement un problème si je veux contrôler ce que l'SelectedItem initial de la zone de liste déroulante est. En utilisant le système de messagerie de MVVM lumière, j'ai actuellement il mis en place où le poseur de propriété SelectedItem du ViewModel est une mise à jour et la diffusion de la l'autre registre ViewModels intéressés par le message dans leurs constructeurs. Il semble que je suis actuellement en train de mettre le SelectedItem via le ViewModel au moment de la construction, qui n'a pas permis de sous-ViewModels à construire et enregistrer encore.

Quelle serait la façon la plus propre de coordonner la charge des données et réglage initial de SelectedItem dans le ViewModel? Je veux vraiment coller avec mettre aussi peu dans le code-behind de la vue comme raisonnable. Je pense que je dois juste une façon pour le ViewModel de savoir quand des choses est chargé et qu'il peut alors continuer à charger les données et finaliser la phase de configuration.

Merci d'avance pour vos réponses.

Était-ce utile?

La solution

Pour les événements que vous devez utiliser le EventToCommand dans MVVM Lumière Toolkit. L'utilisation de ce que vous pouvez lier tout état de cause de tout élément uipour RelayCommand. Consultez son article sur EventToCommand à

http://blog.galasoft.ch/archive/2009/11/05/mvvm-light-toolkit-v3-alpha-2-eventtocommand-behavior.aspx

Télécharger l'échantillon et un coup d'oeil. C'est bien. Vous aurez pas besoin de codebehind alors. Un exemple est le suivant:

<Page x:Class="cubic.cats.Wpf.Views.SplashScreenView"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
      xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras"
      mc:Ignorable="d" 
      d:DesignHeight="300" d:DesignWidth="300"
    Title="SplashScreenPage">

    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Loaded">
            <cmd:EventToCommand Command="{Binding LoadedCommand}" />
        </i:EventTrigger>        
    </i:Interaction.Triggers>

    <Grid>
        <Label Content="This is test page" />
    </Grid>
</Page>

et le mode d'affichage pourrait être comme ça

 public class SplashScreenViewModel : ViewModelBase
    {
        public RelayCommand LoadedCommand
        {
            get;
            private set;
        }

        /// <summary>
        /// Initializes a new instance of the SplashScreenViewModel class.
        /// </summary>
        public SplashScreenViewModel()
        {
            LoadedCommand = new RelayCommand(() =>
            {
                string a = "put a break point here to see that it gets called after the view as been loaded";
            });
        }
    }

si vous voulez le modèle de vue d'avoir les EventArgs, vous pouvez simplement ensemble PassEventArgsToCommand true:

<i:Interaction.Triggers>
            <i:EventTrigger EventName="Loaded">
                <cmd:EventToCommand PassEventArgsToCommand="True" Command="{Binding LoadedCommand}" />
  </i:EventTrigger>        
</i:Interaction.Triggers>

et le modèle de vue sera comme

public class SplashScreenViewModel : ViewModelBase
{
    public RelayCommand<MouseEventArgs> LoadedCommand
    {
        get;
        private set;
    }

    /// <summary>
    /// Initializes a new instance of the SplashScreenViewModel class.
    /// </summary>
    public SplashScreenViewModel()
    {
        LoadedCommand = new RelayCommand<MouseEventArgs>(e =>
        {
            var a = e.WhateverParameters....;
        });
    }

}

Autres conseils

La solution suivante est similaire à celui déjà prévu et accepté, mais il ne se sert pas d'une commande dans le modèle en vue de charger les données, mais un « procédé normal ». Je pense que les commandes sont plus adaptés pour les actions de l'utilisateur (commandes peuvent être disponibles et non disponibles lors de l'exécution), c'est pourquoi utiliser un appel régulier de la méthode, mais aussi en définissant un déclenchement d'interaction dans la vue.

Je suggère ceci: Créer une classe de modèle de vue. Instancier la classe modèle de vue dans le XAML de la vue en créant à l'intérieur de la propriété DataContext.

Mettre en oeuvre un procédé pour charger les données dans le modèle de vue, par exemple, LoadData. Mettre en place la vue, de sorte que cette méthode est appelée lorsque la charge de la vue. Cela se fait par un déclencheur d'interaction dans votre point de vue qui est lié à la méthode dans le modèle de vue (les références à « Microsoft.Expression.Interactions » et « System.Windows.Interactivity » sont nécessaires):

Voir (XAML):

<Window x:Class="MyWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Test" 
    xmlns:viewModel="clr-namespace:ViewModels"
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"            
    >
<Window.DataContext>
    <viewModel:ExampleViewModel/>
</Window.DataContext>
<i:Interaction.Triggers>
    <i:EventTrigger EventName="Loaded">
        <ei:CallMethodAction TargetObject="{Binding}" MethodName="LoadData"/>
    </i:EventTrigger>
</i:Interaction.Triggers>   

appellera la méthode LoadData dans le ViewModel lors de l'exécution lorsque la vue est chargé. C'est là que vous chargez vos données.

public class ExampleViewModel
{
    /// <summary>
    /// Constructor.
    /// </summary>
    public ExampleViewModel()
    {
        // Do NOT do complex stuff here
    }


    public void LoadData()
    {
        // Make a call to the repository class here
        // to set properties of your view model
    }

Si la méthode dans le référentiel est une méthode async, vous pouvez faire la méthode LoadData async aussi, mais ce n'est pas nécessaire dans chaque cas.

Par ailleurs, en général, je ne charger des données dans le constructeur du modèle de vue. Dans l'exemple ci-dessus le constructeur du modèle de vue (paramètre moins) est appelé lorsque le concepteur montre la vue. Faire des choses complexes ici peut provoquer des erreurs dans le concepteur lors de l'affichage de votre vue (pour la même raison que je ne voudrais pas faire des choses complexes dans le constructeur de vues).

Dans un code de scénarios dans la vue constructeur de modèles peut même causer des problèmes lors de l'exécution, lorsque la vue des modèles constructeurs exécute, définir les propriétés du modèle de vue qui sont liés à des éléments de la vue, alors que l'objet de la vue est pas complètement fini de créer .

Ok, alors. : -)

Vous pouvez lier à une méthode dans le ViewModel en utilisant un comportement.

Voici un lien qui vous aidera à cela. http://expressionblend.codeplex.com/

J'ai décidé d'avoir juste le XAML déclarative lié à un gestionnaire d'événements Loaded sur le code-behind de la vue, ce qui vient d'appeler une méthode sur l'objet ViewModel, par l'intermédiaire de l'élément racine UserControl DataContext de la vue.

Il a été, avant tout droit assez simple, et d'une solution propre. Je suppose que j'espérais un moyen de lier l'événement Loaded à l'objet ViewModel de la même manière déclarative vous pouvez avec ICommands dans le XAML.

j'ai donné Klinger le crédit de réponse officielle, mais il a posté un commentaire à ma question, et non une réponse. Donc, je lui ai donné au moins un un sur son commentaire.

J'ai eu ce même problème lorsqu'ils traitent avec des messages entre une fenêtre parent et une fenêtre enfant. Il suffit de changer l'ordre dans lequel vos modèles sont créés dans vue votre classe ViewModelLocator. Assurez-vous que tous les modèles de vue qui dépendent d'un message sont créés avant le modèle d'affichage qui envoie le message.

Par exemple, dans le constructeur de votre classe ViewModelLocator:

public ViewModelLocator()
{
    if (s_messageReceiverVm == null)
    {
        s_messageReceiverVm = new MessageReceiverVM();
    }

    if (s_messageSenderVm == null)
    {
        s_messageSenderVm = new MessageSenderVM();
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top