Pregunta

Mi pregunta genérica es como dice el título, es lo mejor para los datos de carga durante la construcción o modelo de vista después a través de un manejo evento Loaded?

supongo que la respuesta es después de la construcción a través de algún manejo de eventos Loaded, pero me pregunto cómo se coordina más limpia entre el modelo de vista y Vista?

Aquí hay más detalles acerca de mi situación y el problema particular que estoy tratando de resolver:

Estoy utilizando el marco MVVM Light, así como la Unidad de DI. Tengo algunos Vistas anidados, cada uno unido a un modelo de vista correspondiente. Los ViewModels están obligados a DataContext control de la raíz de cada vista a través de la idea de que ViewModelLocator Laurent Bugnion ha puesto en MVVM Light. Esto permite encontrar ViewModels a través de un recurso estático y para controlar el tiempo de vida de ViewModels a través de un marco de inyección de dependencia, en este caso la Unidad. También permite Expression Blend para ver todo en lo que respecta a ViewModels y cómo enlazar ellos.

Así que de todos modos, tengo una vista padre que tiene un enlace de datos ComboBox a una ObservableCollection en su modelo de vista. SelectedItem del ComboBox también está obligado (bidireccional) a una propiedad en el modelo de vista. Cuando la selección del cuadro combinado cambia, esto es a las actualizaciones de activación en otros puntos de vista y subvistas. Actualmente estoy cumpliendo este a través del sistema de mensajería que se encuentra en MVVM Light. Esto es todo funcionando muy bien y como se esperaba cuando se elige diversos artículos en el cuadro combinado.

Sin embargo, el modelo de vista es cada vez sus datos durante el tiempo de construcción a través de una serie de inicialización de llamadas a métodos. Esto sólo parece ser un problema si quiero controlar lo que el SelectedItem inicial del cuadro combinado es. Utilizando el sistema de mensajería de MVVM Light, que actualmente tengo configurado en la incubadora de la propiedad SelectedItem del modelo de vista es el de la difusión de la actualización y los otros ViewModels interesadas se registren para el mensaje en sus constructores. Parece Actualmente estoy tratando de establecer el SelectedItem a través del modelo de vista en el momento de la construcción, que no ha permitido sub-ViewModels a construirse y se registran todavía.

¿Cuál sería la forma más limpia para coordinar la carga de datos y la configuración inicial de SelectedItem dentro del modelo de vista? Realmente quiero seguir con poner tan poco en la vista de código subyacente que sea razonable. Creo que sólo hay una forma de que el modelo de vista para saber cuando las cosas se ha cargado y que a continuación, puede seguir para cargar los datos y finalizar la fase de configuración.

Gracias de antemano por sus respuestas.

¿Fue útil?

Solución

Para eventos que debe utilizar el EventToCommand en MVVM Light Toolkit. El uso de este puede enlazar cualquier caso de cualquier elemento ui para RelayCommand. Echa un vistazo a su artículo sobre EventToCommand a

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

Descargar la muestra y echar un vistazo. Es genial. No se necesita ningún código subyacente a continuación. Un ejemplo es el siguiente:

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

y el modo de vista podría ser como este

 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 desea que el modelo de vista de tener los EventArgs, que pueda facilitar la instalación PassEventArgsToCommand true:

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

y el modelo de vista será como

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

}

Otros consejos

La siguiente solución es similar a la ya proporcionado y aceptado, pero que no utiliza un comando en el modelo de vista para cargar los datos, pero un "método normal". Creo que los comandos son más adecuados para las acciones del usuario (comandos pueden estar disponibles y no está disponible en tiempo de ejecución), que es la razón por la utilización de una llamada a un método regular, sino también mediante el establecimiento de un gatillo de una interacción en la vista.

Le sugiero esto: Crear una clase de vista del modelo. Instancia de la clase vista del modelo en el XAML de la vista mediante la creación dentro de la propiedad DataContext.

Implementar un método para cargar los datos en su modelo de vista, por ejemplo, LoadData. Configurar la vista, por lo que este método se llama cuando la vista cargas. Esto se hace mediante un disparador de interacción en la vista que está vinculada con el método en el modelo de vista (las referencias a "Microsoft.Expression.Interactions" y "System.Windows.Interactivity" son necesarios):

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

Esto llamar al método LoadData en el ViewModel en tiempo de ejecución cuando se carga la vista. Aquí es donde se cargan los datos.

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 el método en el repositorio es un método asíncrono, puede hacer que el método asíncrono LoadData también, pero esto no es necesario en cada caso.

Por cierto, en general, yo no cargar los datos en el constructor del modelo de vista. En el ejemplo anterior el (parámetro menos) constructor del modelo de vista se llama cuando el diseñador muestra su vista. Hacer las cosas complejas aquí puede causar errores en el diseñador al mostrar su punto de vista (por la misma razón por la que no haría las cosas complejas en el vistas constructor).

En algún código de escenarios en la vista de los modelos de constructor puede incluso causar problemas en tiempo de ejecución, cuando los modelos de vista de constructores ejecuta, propiedades de deformación del modelo de vista que están unidos a elementos de la vista, mientras que el objeto de vista no está creando completamente terminado .

Ok, entonces. : -)

Se puede obligar a un método en el modelo de vista mediante el uso de un comportamiento.

Aquí hay un enlace que le ayudará con eso. http://expressionblend.codeplex.com/

decidí ir a tomar el XAML declarativa unido a un controlador de eventos cargados en código subyacente de la vista, que a su vez acaba de llamar a un método en el objeto modelo de vista, a través de elemento raíz de la vista de control de usuario DataContext.

Fue una solución bastante simple, sencillo y limpio. Supongo que estaba esperando una manera de unir el evento Loaded al objeto modelo de vista de la misma manera declarativa que puede con ICommands en el XAML.

Me pudo haber dado el crédito oficial Klinger respuesta, pero publicado un comentario a mi pregunta, y no una respuesta. Así que al menos le dio un one-up en su comentario.

he tenido este mismo problema cuando se trata de mensajes entre una ventana principal y una ventana secundaria. Sólo cambia el orden en que sus modelos de vista se crean en su clase ViewModelLocator. Asegúrese de que todos los modelos de vista que son dependientes de un mensaje se crean antes de que el modelo de vista que envía el mensaje.

Por ejemplo, en el constructor de la clase ViewModelLocator:

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

    if (s_messageSenderVm == null)
    {
        s_messageSenderVm = new MessageSenderVM();
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top