2012-04-19 15 views
36

He estado jugando con dónde poner "¿estás seguro?" escribe mensajes en mi aplicación MVVM WPF."¿Estás seguro?" indicaciones. ¿Parte del ViewModel o simplemente la vista?

Me inclino a pensar que estos son puramente parte de la Vista. Si ViewModel expone un DeleteCommand, entonces esperaría que ese comando se elimine inmediatamente.

Para integrar estas solicitudes en ViewModel, debería exponer una propiedad RequestDeleteCommand separada, una DeletePromptItem para enlazar la solicitud, y que también podría funcionar como activador para mostrar la solicitud.

Incluso con esto, no hay nada que impida a una prueba de unidad llamando DeleteCommand directamente, a menos que puse lógica específica en el modelo de vista para requerir DeletePromptItem para que coincida con el elemento suministrado como argumento para DeleteCommand.

Sin embargo, todo esto me parece ruido en ViewModel. El mensaje es más un problema de la interfaz de usuario para protegerse de misclicks, etc. Para mí, esto sugiere que debería estar en la vista con un mensaje confirmado llamando a DeleteCommand.

¿Alguna idea?

+6

¿Qué pasa con "Este archivo ya existe. ¿Desea sobrescribirlo?" tipo de indicaciones? –

+0

Buena pregunta. No lo sé. Tendrás que pensar en eso. – GazTheDestroyer

+0

como dije en mi respuesta. ponga la lógica de la aplicación en el modelo de vista y use un servicio para mostrar sus diálogos. – blindmeis

Respuesta

16

El incita definitivamente no debe ser parte del modelo de vista, pero esto no significa necesariamente que la mejor solución es codificar ellos en la Vista (aunque ese es un primer acercamiento muy razonable).

Existen dos alternativas que conozco que pueden reducir el acoplamiento entre View y ViewModel: usar un servicio de interacción y disparar solicitudes de interacción. Ambos se explican muy bien here; es posible que desee echar un vistazo.

La idea general es que abstraas cómo se realizan las interacciones asíncronas y funcionan con algo más similar a la lógica basada en eventos , al mismo tiempo que permite que ViewModel exprese que quiere interactuar con el usuario como parte de un operación; el resultado neto es que puedes documentar esta interacción y probarla en una unidad.

Editar: debo añadir que he explorado el uso de Prisma 4 con las solicitudes de interacción en un proyecto prototipo y estaba muy satisfechos con los resultados (con un poco de código marco yendo incluso se puede especificar lo que va a suceder en una solicitud de interacción específica en XAML!). Me encantaría dar algunos fragmentos, pero tendrá que esperar para mañana.

+0

+1 para el enlace. El enfoque de Prism parece ser el más cercano a MVVM puro que he encontrado, gracias. La lógica permanece en ViewModel, todos los elementos de la interfaz permanecen en la misma vista. – GazTheDestroyer

9

However, this all just seems like noise in the ViewModel to me. The prompt is more a user interface issue to guard against misclicks etc. To me this suggests it should be in the view with a confirmed prompt calling the DeleteCommand.

Acepto; las solicitudes de este tipo deberían manejarse en la vista, ya que en última instancia, la vista es con lo que el usuario está viendo e interactuando, y no el modelo de vista. Una vez que su vista ha obtenido la confirmación del usuario de que se debe invocar el DeleteCommand, continúe e inícielo en su modelo de vista.

De la manera en que lo veo, las pruebas unitarias en realidad no tienen nada que ver con la interacción del usuario, a menos que esté probando la vista.

+0

Creo que he cambiado de opinión. Para el ejemplo específico limitado que di la vista, solo el método funciona bien, pero para cualquier tipo de interacción basada en lógica, como el comentario de Nicolas, entonces el ViewModel debe estar involucrado. – GazTheDestroyer

+0

Eso funcionaría también. Él hace un buen punto. – BoltClock

3

Sugiero hacerlo a través de un servicio que gestiona las ventanas modales. Me he enfrentado a este problema hace bastante tiempo, tampoco. This blog me ayudó mucho.

Aunque es una publicación de Silverlight, no debería diferir demasiado, en comparación con wpf.

0

Personalmente, creo que es sólo una parte de la opinión de que no hay datos

1

Resuelvo este tipo de problema usando el patrón EventAggregator.

Se puede ver explicó here

1

Creo que depende de la indicación, pero en términos generales la lógica del código que necesita para solicitar al usuario está a menudo en el modelo de vista de todos modos, por ejemplo, el usuario ha pulsado un botón para eliminar un elemento de la lista, se dispara un comando en la máquina virtual, se ejecuta la lógica y es aparente que esto puede afectar a otra entidad, el usuario debe elegir lo que desea hacer, en este punto no debería poder solicitar la vista para avisar al usuario, así que no pude ver ninguna otra opción más que manejarla en la máquina virtual. Es algo que siempre he estado incómodo con pero simplemente escribí un método de confirmación en mi base de VM, que llama a un servicio de diálogo para dsiplay el mensaje y devuelve un verdadero o falso:

/// <summary> 
    /// A method to ask a confirmation question. 
    /// </summary> 
    /// <param name="messageText">The text to you the user.</param> 
    /// <param name="showAreYouSureText">Optional Parameter which determines whether to prefix the message 
    /// text with "Are you sure you want to {0}?".</param> 
    /// <returns>True if the user selected "Yes", otherwise false.</returns> 
    public Boolean Confirm(String messageText, Boolean? showAreYouSureText = false) 
    { 
     String message; 
     if (showAreYouSureText.HasValue && showAreYouSureText.Value) 
      message = String.Format(Resources.AreYouSureMessage, messageText); 
     else 
      message = messageText; 

     return DialogService.ShowMessageBox(this, message, MessageBoxType.Question) == MessageBoxResult.Yes; 
    } 

Para mí esta es una de esas áreas grises cruzadas a las que a veces no puedo obtener una respuesta firme en MVVM, así que estoy interesado en enfoques de poesía.

1

Tener un vistazo a esto:

MVVM and Confirmation Dialogs

Puedo utilizar una técnica similar en mis modelos de vista, porque creo que es parte del modelo de vista para preguntar si se va a proceder con la supresión o no y no de ningún objeto visual o vista. Con la técnica descrita, su modelo no se refiere a ninguna referencia visual que no me guste sino a algún tipo de servicio que llame a un cuadro de diálogo de confirmación o un cuadro de mensaje o cualquier otra cosa.

7

En mi opinión, lo que provocó que el usuario se compone de dos partes:

  1. La lógica que determina si o no el indicador se debe mostrar y qué se debe hacer con el resultado
  2. El código que realmente espectáculos el mensaje

La parte 2 claramente no pertenece al ViewModel.
Pero la parte 1 no pertenece allí.

Para hacer posible esta separación, uso un servicio que puede ser utilizado por ViewModel y para el cual puedo proporcionar una implementación específica para el entorno en el que me encuentro (WPF, Silverlight, WP7).

Esto conduce a un código como éste:

interface IMessageBoxManager 
{ 
    MessageBoxResult ShowMessageBox(string text, string title, 
            MessageBoxButtons buttons); 
} 

class MyViewModel 
{ 
    IMessageBoxManager _messageBoxManager; 

    // ... 

    public void Close() 
    { 
     if(HasUnsavedChanges) 
     { 
      var result = _messageBoxManager.ShowMessageBox(
          "Unsaved changes, save them before close?", 
          "Confirmation", MessageBoxButtons.YesNoCancel); 
      if(result == MessageBoxResult.Yes) 
       Save(); 
      else if(result == MessageBoxResult.Cancel) 
       return; // <- Don't close window 
      else if(result == MessageBoxResult.No) 
       RevertUnsavedChanges(); 
     } 

     TryClose(); // <- Infrastructure method from Caliburn Micro 
    } 
} 

Este enfoque puede ser fácilmente utilizado no sólo para mostrar un cuadro de mensaje, sino también para mostrar otras ventanas, como se explica en this answer.

+0

+1 Agradable desglose y separación de preocupaciones. – BoltClock

+2

No estoy seguro si esto separa preocupaciones. Ahora tiene un mensaje de recuadro de mensaje codificado en ViewModel. ¿Qué sucede si la vista quiere hacer la confirmación de otra manera, como arrastrar y soltar, o incluso una respuesta escrita a máquina? El ViewModel no debe saber nada sobre esas cosas. – GazTheDestroyer

+0

No creo entender su pregunta. El cuadro de mensaje es una construcción abstracta. Cómo se implementa no está definido por ViewModel. La implementación concreta para WP7 podría mostrar el texto y pedirle que arrastre el texto en una de las tres casillas. Uno de los cuadros tiene el significado de "Sí", uno de "No" y uno de "Cancelar". Todavía tiene la misma semántica. –

0

La forma en que lo he manejado en el pasado es colocar un evento en el modelo de vista que se dispara cuando se debe mostrar el cuadro de diálogo.La vista se engancha en el evento y se maneja mostrando el cuadro de diálogo de confirmación, y devuelve el resultado a la persona que llama a través de sus EventArgs.

1

Creo que las preguntas "¿Estás seguro?" Pertenecen al modelo de vista porque es aplicación lógica y no cosas ui puras como animaciones y más.

así que la mejor opción sería en el método deletecommand execute para llamar a "Are you sure" service dialog.

EDIT: Código modelo de vista

IMessageBox _dialogService;//come to the viewmodel with DI 

    public ICommand DeleteCommand 
    { 
     get 
     { 
      return this._cmdDelete ?? (this._cmdDelete = new DelegateCommand(this.DeleteCommandExecute, this.CanDeleteCommandExecute)); 
     } 
    } 

poner la lógica en el método de ejecución

private void DeleteCommandExecute() 
    { 
     if (!this.CanDeleteCommandExecute()) 
     return; 

     var result = this.dialogService.ShowDialog("Are you sure prompt window?", YesNo); 

     //check result 
     //go on with delete when yes 
    } 

el servicio de diálogo puede ser cualquier cosa que desee, pero la lógica de la aplicación para comprobar antes de eliminar está en su modelo de vista .

Cuestiones relacionadas