2010-02-10 23 views
6

Mi proyecto WPF será organizados así:desacoplar las pantallas sin cuerdas mágicas

Screens 
    Group1 
     Screen1 
     View.xaml 
     ViewModel.cs 
    Group2 
     Screen2 
     View.xaml 
     ViewModel.cs 

Para mostrar el Screen1 del Screen2 voy a utilizar algo como esto: ScreenManager.Show("Group1.Screen1") Esta apariencia (utilizando la reflexión) en el Screens.Group1.Screen1 espacio de nombres para una vista y un modelo de vista y los crea una instancia.

¿Cómo puedo eliminar la cadena mágica sin acoplamiento Screen1 y Screen2 (no quiero que las clases en Screen2 utilizar el espacio de nombres Screen1). También me gustaría algún tipo de descubrimiento de pantalla (autocompletado/intellisense)

O tal vez de alguna manera (prueba de automatización) para verificar que todas las llamadas a ScreenManager.Show son válidas.

Actualización: me ocurrió esto:

public class ScreenNames 
{ 
    public Group1Screens Group1; 

    public class Group1Screens 
    { 
     public ScreenName Screen1; 
    } 
} 

public sealed class ScreenName 
{ 
    private ScreenName() { } 
} 

public class ScreenManager : IScreenManager 
{ 
    public void Show(Expression<Func<ScreenNames, ScreenName>> x) {} 
} 

Uso:

screenManager.Show(x=>x.Group1.Screen1); 

No es ideal pero supongo violando DRY es aún mejor que las cadenas mágicas. Y puedo probar automáticamente (con reflejo) que todas las llamadas son válidas.

+0

¿Por qué Screen2 necesita saber acerca de Screen1? ¿No existe el administrador de pantalla fuera de cada una de las pantallas? Y con Intellisense, ¿está diciendo que durante el desarrollo desea que cada uno de los nombres de la pantalla aparezca en la lista desplegable cuando comienza a escribir ScreenManager.Show()? ¿La lista de pantallas estática o dinámica (cargada en tiempo de ejecución)? – Dave

+0

Eventualmente pasaré un parámetro; ScreenManager será una propiedad de ViewModel; Para intellisense, creo que una lista estática es imprescindible:/ Creo que podría tener algo como esto: ScreenManager.Show (x => x.Group1.Screen1) –

+0

uso como ScreenManager.Show (x => x.Group1.Screen1) significa que tendré que mantener y mantener una lista separada de pantallas, pero creo que no hay otra manera si quiero intellisense –

Respuesta

3

No necesita todas las cosas de ScreenManager en WPF, porque el motor DataTemplate puede encargarse de esto con un marcado puro.

Simplemente puede enlazar datos de un área particular de su aplicación con un ContentPresenter y un montón de DataTemplates. Vincular el área a una propiedad de un modelo de vista 'raíz', y dejar que el 'raíz' ViewModel implemente INotifyPropertyChanged para que WPF sepa si usted cambia el ViewModel en esa área.

public class RootViewModel : INotifyPropertyChanged 
{ 
    public object Screen1ViewModel { get; } 

    public object Screen2ViewModel { get; } 
} 

databind control de uno ContentPresenter a la propiedad Screen1ViewModel usando

<ContentControl Content="{Binding Path=Screen1ViewModel}" /> 

y lo mismo para la siguiente. Cuando necesite cambiar el contenido de Screen1, simplemente reasigne Screen1ViewModel del código, y debido al evento PropertyChanged elevado, WPF lo recogerá y vinculará el nuevo ViewModel a una nueva Vista.

Los DataTemplates pueden ser tan simple como esto:

<Window.Resources> 
    <DataTemplate DataType="{x:Type foo:MyViewModel}"> 
     <self:MyControl /> 
    </DataTemplate> 
    <DataTemplate DataType="{x:Type foo:MyOtherViewModel}"> 
     <self:MyOtherControl /> 
    </DataTemplate> 
</Window.Resources> 

En caso de que no está familiarizado con él, this article on MVVM in WPF es una excelente introducción.

+0

Gracias por su respuesta, no estoy seguro de que completamente entendido, pero aún no responde a mi pregunta: ¿cómo mantener desacoplado el ViewModel? No quiero que Screen2 ViewModel use directamente la pantalla1 –

+0

@Mark: me gusta mucho este enfoque, pero no estoy seguro de si esto es lo que persigue Catalin. Casi me parece que quiere implementar una especie de navegación y poder ir de una página a otra. Si entiendo tu enfoque, sugieres cambiar el modelo de vista a través de enlace de datos, lo cual es genial, pero no sé si eso es lo que él busca. Por cierto, ¿puedes recomendar alguna buena lectura en línea que incluya ejemplos en los que quieras cambiar ViewModels? Siempre tengo una relación 1: 1: 1 entre View: ViewModel: Model y nunca cambio el ViewModel (porque no conozco sus ventajas). – Dave

+0

@Catalin DICU: en este modelo, Screen1ViewModel no sabe nada acerca de Screen2ViewModel y viceversa. RootViewModel obviamente sabe acerca de ambos, pero tenga en cuenta que ambas propiedades se declaran como el tipo System.Object, lo que significa que realmente pueden ser cualquier cosa. Si no desea obtener información sobre los tipos de VM en RootViewModel, puede usar DI para inyectar las máquinas virtuales en RootViewModel. Esto le daría un constructor como 'RootViewModel (objeto vm1, objeto vm2)'. –

Cuestiones relacionadas