2010-01-01 19 views
14

Recientemente comencé a investigar el patrón de MVVM con WPF para un próximo proyecto. Empecé con Josh Smith's MSDN article. Tengo una pregunta (bueno muchos, pero empecemos con uno):MVVM (con WPF) - Enlace de varias vistas al mismo modelo de vista

Tengo un modelo de vista individual que expone las propiedades del modelo. Necesito dos vistas, "Agregar individuo" y "Editar individuo", que son muy similares a las que pueda imaginar. Lo que he hecho actualmente es tener 2 subclases AddIndividualViewModel y EditIndividualViewModel que exponen los comandos Agregar y Editar, respectivamente. También tengo 2 vistas nombradas similares que se unen a estos.

Ahora, este método funciona y estas clases son bastante pequeñas de todos modos, pero me pregunto si es posible para mí tener solo el modelo de una vista, que expone ambos comandos. Todavía tendría 2 vistas que se unirían a este mismo modelo de vista, exponiendo el comando apropiado como un botón. No estoy muy seguro de cómo hacer esto. En los principales recursos de la ventana que tengo algo así como:

 <DataTemplate DataType="{x:Type ViewModels:AddIndividualViewModel}"> 
      <Views:AddIndividualView /> 
     </DataTemplate> 

Con este método de unión que sólo puede tener un uno-a-uno vinculante, es decir, el mismo punto de vista se muestra siempre por un modelo de vista determinado. ¿Hay alguna manera de cambiar automáticamente la vista dependiendo de una propiedad en el modelo de vista (por ejemplo, IndividualViewModel.Mode). ¿Hay un enfoque diferente que debería considerar?

Tenga en cuenta que la ventana principal tiene una colección de modelos de vista y muestra cada uno en la pestaña.

Gracias!

Respuesta

1

No hay ninguna razón por la que no deba ser capaz de lograrlo. Una forma de hacerlo es proporcionar un indicador en su modelo de vista que indique si está en el modo agregar o en el modo de edición, y diseñar su vista de acuerdo con esa bandera usando enlaces simples, desencadenantes o selectores de plantilla.

Como referencia puede mirar en Sacha Barber's DataWrapper class que es parte de su marco Cinch (no es directamente aplicable a su caso, pero es un buen punto de partida) que envuelve los campos de datos en el modelo de vista de tal manera para apoyar una bandera para alternar entre solo lectura (ver modo de grabación), y lectura y escritura (edición de modo de grabación). Puede aplicar un enfoque similar para hacer la distinción entre agregar y editar.

Básicamente, en lugar de tener propiedades simples en su modelo de vista, crea una instancia de una clase contenedora de datos que incluye una propiedad Value y una propiedad IsAdding. En su opinión, puede usar enlaces, desencadenantes o selectores de plantilla para modificar plantillas basadas en esa propiedad.

4

¡Gracias por apuntarme en la dirección correcta! Todavía soy nuevo con WPF y conozco las diferentes posibilidades, incluidos los métodos de enlace. De todos modos para cualquier persona interesada, aquí está la solución que llegué para este caso particular:

Decidí que quería mantener los modelos de vista separados en dos subclases AddIndividualViewModel y EditIndividualViewModel que solo exponen comandos, en lugar de tratar de administrar el estado en el una clase. Sin embargo, quería una vista para no duplicar el XAML.Terminé usando dos DataTemplates y DataTemplateSelector para cambiar los botones de acción en función del modelo de vista:

 <DataTemplate x:Key="addTemplate"> 
      <Button Command="{Binding Path=AddCommand}">Add</Button> 
     </DataTemplate> 

     <DataTemplate x:Key="editTemplate"> 
      <Button Command="{Binding Path=UpdateCommand}">Update</Button> 
     </DataTemplate> 

     <TemplateSelectors:AddEditTemplateSelector 
      AddTemplate="{StaticResource addTemplate}" 
      EditTemplate="{StaticResource editTemplate}" 
      x:Key="addEditTemplateSelector" /> 

y un presentador de contenido en la parte inferior de la forma:

 <ContentPresenter Content="{Binding}" 
          ContentTemplateSelector="{StaticResource addEditTemplateSelector}" /> 

Aquí está el código de el selector de plantilla:

class AddEditTemplateSelector : DataTemplateSelector 
{ 
    public DataTemplate AddTemplate { get; set; } 
    public DataTemplate EditTemplate { get; set; } 

    public override DataTemplate SelectTemplate(object item, DependencyObject container) 
    { 
     if (item is AddIndividualViewModel) 
     { 
      return AddTemplate; 
     } 
     else if (item is EditIndividualViewModel) 
     { 
      return EditTemplate; 
     } 

     return null; 
    } 
} 

esto puede o no ser cómo implementar la última cosa (teniendo en cuenta los requisitos), pero es bueno ver que tengo este tipo de opción disponible.

1

Para esta tarea no necesita ningún DataTemplateSelector en absoluto.

  1. Deducir tanto EditIndividualVM y AddINdividualVM de IndividualVM.
  2. Editar y AddCommands dirigen a una propiedad setter en el IndividualVM.
  3. El setter VM = new AddIndividualVM o VM = new EditIndividualVM dependiendo del botón que se presione.
  4. en XAML que se unen en el contentgrid a su propiedad VM así:

+2

Parece que tiene el código que falta. ¿Podría actualizar su respuesta con el fragmento de código por favor? – PlagueHammer

4

Así que hay 2 puntos de vista diferentes sobre la base de un valor de propiedad. Una cosa a considerar es refactor your presentation code, por lo que en lugar de los valores de una propiedad podría tener subclases reales. Luego puede usar 2 DataTemplate diferentes para cada clase.

<DataTemplate DataType="{x:Type ViewModels:AddIndividualViewModel}"> 
    <Views:AddIndividualView /> 
</DataTemplate> 

<DataTemplate DataType="{x:Type ViewModels:EditIndividualViewModel}"> 
    <Views:EditIndividualView /> 
</DataTemplate> 

Si usted piensa que es una exageración, se puede utilizar un disparador y envolver sus puntos de vista específicos en una ContentPresenter.

<DataTemplate x:Key="AddIndividualTemplate" DataType="{x:Type ViewModels:IndividualViewModel}"> 
    <Views:AddIndividualView /> 
</DataTemplate> 

<DataTemplate x:Key="EditIndividualTemplate" DataType="{x:Type ViewModels:IndividualViewModel}"> 
    <Views:EditIndividualView /> 
</DataTemplate> 

<DataTemplate DataType="{x:Type ViewModels:IndividualViewModel}"> 
    <ContentPresenter Content="{Binding}"> 
    <ContentPresenter.Style> 
     <Style TargetType="ContentPresenter"> 
     <Setter Property="ContentTemplate" Value="{StaticResource AddIndividualTemplate}" /> 
     <Style.Triggers> 
      <DataTrigger Binding="{Binding Mode}" Value="{x:Static ViewModels:IndividualMode.Edit}"> 
      <Setter Property="ContentTemplate" Value="{StaticResource EditIndividualTemplate}" /> 
      </DataTrigger> 
     </Style.Triggers> 
     </Style> 
    </ContentPresenter.Style> 
    </ContentPresenter> 
</DataTemplate> 
+0

Esta es la clásica solución MVVM. Especifica las dos opciones y no tiene código. –

Cuestiones relacionadas