mvc ejemplo mvvm silverlight-4.0 mvvm-light wcf-ria-services

ejemplo - mvvm vs mvc



¿A dónde pertenece la lógica de navegación, View, ViewModel u otra parte? (2)

Advertencia: alerta de novato de MVVM obstinada :) (Soy muy nuevo en MVVM, pero lo disfruto mucho hasta el momento).

Buena pregunta. Descubrí que es perfectamente posible (aunque un poco feo en algunos lugares) burlar el NavigationService y pasar un servicio de INavigationService a un ViewModel. De hecho, incluso puede hacer que la interfaz sea ligeramente más agradable con los genéricos, para pasar un tipo (como un argumento de tipo) en lugar de un URI de cadena.

Sin embargo, he descubierto que me he deshecho un poco cuando se trata de colocar los datos adicionales involucrados en la navegación ... No he encontrado un buen lugar para hacer toda la codificación / descodificación para propagar el estado de forma clara. Sospecho que ViewModelFactory bien puede ser parte de esa ecuación ...

Por lo tanto, aún no es una solución perfecta, pero al menos ViewModel puede ser responsable de la acción de "navegar ahora" (o "volver atrás").

I un botón en una vista, vinculado a una propiedad ICommand de ViewModel (en realidad es RelayCommand de mvvv-light)

Si el usuario hace clic en el botón, quiero navegar a una nueva vista. Por supuesto, NavigationService es parte de View, no ViewModel. Eso implica que la navegación es responsabilidad de View? Pero en mi caso, la vista que iré cuando se haga clic en el botón depende de muchos factores, incluido quién es el usuario conectado, el estado en que se encuentra la base de datos, etc. Seguramente, la Vista no debería necesitar todo Esa información.

¿Cuál es la opción preferida para ejecutar una llamada NavigationService.Navigate?


Si ya está utilizando MVVM Light, una opción es hacer uso del bus de mensajes que incluye. Así que vincula su botón a un RelayCommand en el modelo de vista, como ya dijo que ya está haciendo. En el controlador para su RelayCommand, puede tomar la decisión de a qué vista navegar. Esto mantiene toda esa lógica en el modelo de vista.

Una vez que el manejador de comandos haya decidido a qué vista navegar, puede publicar un mensaje en el bus de mensajes. Su vista escuchará ese mensaje y luego usará NavigationService para realizar la navegación. Por lo tanto, no está haciendo otra cosa que esperar a que le digan que navegue en algún lugar y luego navegue donde se lo dice.

He estado haciendo esto definiendo una clase de NavigationMessage que mis modelos de vista pueden publicar, y una clase base de vista que mi vista hereda de la que contiene el oyente. El NavigationMessage se ve así:

public class NavigationMessage : NotificationMessage { public string PageName { get { return base.Notification; } } public Dictionary<string, string> QueryStringParams { get; private set; } public NavigationMessage(string pageName) : base(pageName) { } public NavigationMessage(string pageName, Dictionary<string, string> queryStringParams) : this(pageName) { QueryStringParams = queryStringParams; } }

Esto permite simplemente pasar el nombre de la página u opcionalmente también incluir los parámetros necesarios de la cadena de consulta. Un manejador de RelayCommand publicaría este mensaje así:

private void RelayCommandHandler() { //Logic for determining next view, then ... Messenger.Default.Send(new NavigationMessage("ViewToNavigate")); }

Finalmente, la clase base de vista se ve así:

public class BasePage : PhoneApplicationPage { public BasePage() { Messenger.Default.Register<NavigationMessage>(this, NavigateToPage); } protected void NavigateToPage(NavigationMessage message) { //GetQueryString isn''t shown, but is simply a helper method for formatting the query string from the dictionary string queryStringParams = message.QueryStringParams == null ? "" : GetQueryString(message); string uri = string.Format("/Views/{0}.xaml{1}", message.PageName, queryStringParams); NavigationService.Navigate(new Uri(uri, UriKind.Relative)); } }

Esto supone una convención donde todas las vistas se encuentran en una carpeta "Vistas" en la raíz de la aplicación. Esto funciona bien para nuestra aplicación, pero por supuesto, esto podría ampliarse para admitir diferentes escenarios sobre cómo organizar sus vistas.