Domanda

La mia domanda generica è come dice il titolo, è la cosa migliore per caricare i dati durante la costruzione ViewModel o in seguito attraverso alcuni eventi Loaded gestione?

Sto indovinando la risposta è dopo la costruzione attraverso qualche gestione degli eventi Loaded, ma mi chiedo come ciò che è più pulito coordinata tra ViewModel e vista?

Ecco maggiori dettagli su mia situazione e il problema particolare che sto cercando di risolvere:

Sto usando il framework MVVM luce così come l'Unità per DI. Ho alcune Visualizzazioni nidificati, ciascuno associato a un corrispondente ViewModel. I ViewModels sono tenuti a di ogni vista DataContext controllo radice attraverso l'idea che ViewModelLocator Laurent Bugnion ha messo in luce MVVM. Questo permette di trovare ViewModels tramite una risorsa statica e per controllare la durata del ViewModels tramite un framework Dependency Injection, in questo caso l'Unità. Essa consente anche di Expression Blend per vedere tutto in materia di ViewModels e come associare loro.

Comunque, ho una vista padre che ha un databound ComboBox a un ObservableCollection nel suo ViewModel. SelectedItem del ComboBox è anche legato (bidirezionale) per una proprietà sul ViewModel. Quando la selezione dei cambiamenti ComboBox, questo è quello di innescare gli aggiornamenti in altri punti di vista e subviews. Attualmente sto realizzare questo attraverso il sistema di messaggistica che si trova in MVVM Luce. Tutto questo è fantastico lavorare e come previsto quando si sceglie diversi elementi nella casella combinata.

Tuttavia, il ViewModel sta ottenendo i suoi dati durante i tempi di costruzione attraverso una serie di chiamate di metodo di inizializzazione. Questo sembra essere un problema solo se voglio controllare ciò che il SelectedItem iniziale della ComboBox è. Utilizzando il sistema di messaggistica di MVVM Luce, ho attualmente ha istituito dove il setter di proprietà SelectedItem del ViewModel è quella che trasmette l'update e gli altri interessati ViewModels registrarsi per il messaggio nella loro costruttori. Sembra Attualmente sto cercando di impostare il SelectedItem attraverso il ViewModel in fase di costruzione, che non ha permesso sub-ViewModels da costruire e registrare ancora.

Quale sarebbe il modo più pulito per coordinare il carico di dati e l'impostazione iniziale del SelectedItem all'interno del ViewModel? Ho molta voglia di restare con la messa come poco in termini di vista code-behind, come è ragionevole. Credo di aver solo bisogno di un modo per il ViewModel per sapere quando roba è stato caricato e che può quindi continuare a caricare i dati e finalizzare la fase di messa a punto.

Grazie in anticipo per le vostre risposte.

È stato utile?

Soluzione

Per gli eventi è necessario utilizzare l'EventToCommand in MVVM Luce Toolkit. Usando questo è possibile associare ogni caso di qualsiasi elemento ui per relaycommand. Visitate il suo articolo su EventToCommand a

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

Scarica il campione e dare un'occhiata. È ottimo. Non avrete bisogno di alcun codebehind poi. Un esempio è il seguente:

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

e la modalità di visualizzazione potrebbe essere simile a questo

 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";
            });
        }
    }

se si desidera che il modello di vista di avere le EventArgs, è possibile semplice set PassEventArgsToCommand true:

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

e il modello di vista sarà come

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....;
        });
    }

}

Altri suggerimenti

La seguente soluzione è simile a quella già fornita e accettata, ma non utilizza un comando nel modello immagine per caricare i dati, ma un "metodo normale". Credo che i comandi sono più adatti per le azioni dell'utente (comandi possono essere disponibili e non disponibili in fase di esecuzione), che è il motivo per cui l'uso di un metodo normale chiamata, ma anche impostando un un trigger di interazione nella vista.

suggerisco questo: Creare una classe vista del modello. Creare un'istanza della classe vista del modello all'interno del XAML della vista attraverso la creazione di esso all'interno della proprietà DataContext.

implementare un metodo per caricare i dati nel modello di vista, ad esempio, LoadData. Impostare la vista, in modo che questo metodo viene chiamato quando viene caricata vista. Questo è fatto da un trigger di interazione nella vista che è legata al metodo nel modello di visualizzazione (i riferimenti a "Microsoft.Expression.Interactions" e "System.Windows.Interactivity" Occorrono):

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

Questo chiamerà il metodo LoadData nel ViewModel in fase di esecuzione quando la visualizzazione viene caricato. Questo è dove si caricano i dati.

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
    }

Se il metodo nel repository è un metodo asincrono, è possibile effettuare il metodo asincrono LoadData troppo, ma questo non è necessario in ogni caso.

Tra l'altro, in genere non vorrei caricare i dati nel costruttore del modello di vista. Nell'esempio sopra il (parametro meno) Funzione di costruzione del modello di visualizzazione viene chiamato quando il progettista mostra la visuale. Fare le cose complesse qui può causare errori nel progettista quando mostra la visualizzazione (per lo stesso motivo non vorrei fare cose complesse in vista costruttore).

Nel codice scenari nel costruttore vista modelli può anche causare problemi in fase di esecuzione, quando la vista modelli costruttori esegue, impostare le proprietà del modello vista che sono vincolati ad elementi nella vista, mentre l'oggetto vista non è completamente finito creando .

Ok, allora. : -)

È possibile associare a un metodo nel ViewModel utilizzando un comportamento.

Ecco un link che vi aiuterà in questo. http://expressionblend.codeplex.com/

Ho deciso di appena hanno il codice XAML dichiarativo associato a un gestore di eventi Loaded sul del View code-behind, che a sua volta ha appena chiamato un metodo sull'oggetto ViewModel, via della vista dell'elemento radice UserControl DataContext.

E 'stato abbastanza semplice, dritto in avanti, e la soluzione pulita. Credo che speravo in un modo per legare l'evento Loaded all'oggetto ViewModel nello stesso modo dichiarativo è possibile con ICommands in XAML.

Forse ho dato Klinger credito risposta ufficiale, ma ha inviato un commento alla mia domanda, e non una risposta. Così ho almeno dato un one-up sul suo commento.

Ho avuto questo stesso problema quando si tratta di messaggi tra una finestra genitore e una finestra figlio. Basta cambiare l'ordine in cui vengono creati i tuoi modelli vista nella classe ViewModelLocator. Assicurarsi che tutti i modelli vista che dipendono da un messaggio vengono create prima che il modello vista che invia il messaggio.

Per esempio, nel costruttore della classe di ViewModelLocator:

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

    if (s_messageSenderVm == null)
    {
        s_messageSenderVm = new MessageSenderVM();
    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top