2012-06-12 12 views
6

Estoy aprendiendo WPF y MVVM en este momento (o al menos estoy tratando de ...).Cambio de vista en Buttonclick

Creé una pequeña aplicación de muestra, que muestra una ventana con 2 botones, cada uno de ellos debería mostrar una nueva vista al hacer clic. Así que creé 3 UserControls (DecisonMaker con los 2 botones y un control de usuario para cada "clicktarget").

Así que limitan el CotentControl del MainWindow a una propiedad llamada "PresentaciónActual" en mi MainWindowViewModel

Código de MainWindow.xaml:

<Window x:Class="WpfTestApplication.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="clr-namespace:WpfTestApplication" 
    Title="MainWindow" Height="350" Width="525"> 
<Window.DataContext> 
    <local:MainWindowViewModel /> 
</Window.DataContext> 
<Grid> 
    <ContentControl Content="{Binding CurrentView, Mode=OneWay}" /> 
</Grid> 
</Window> 

Código de MainWindowViewModel:

class MainWindowViewModel 
{  
    private UserControl _currentView = new DecisionMaker(); 
    public UserControl CurrentView 
    { 
     get { return _currentView; } 
     set { _currentView = value; } 
    } 

    public ICommand MausCommand 
    { 
     get { return new RelayCommand(LoadMouseView); } 
    } 

    public ICommand TouchCommand 
    { 
     get { return new RelayCommand(LoadTouchView); } 
    } 

    private void LoadMouseView() 
    { 
     CurrentView = new UserControlMouse(); 
    } 

    private void LoadTouchView() 
    { 
     CurrentView = new UserControlTouch(); 
    } 
} 

El UserControl (DecisionMaker) inicial aparece como supuesto. También se llama al método LoadMouseView. Pero la Vista no cambia. ¿Qué me estoy perdiendo?

ACTUALIZACIÓN: ¡Muchísimas gracias! Me perdí la interfaz INotifyPropertyChanged. ¡Todas sus respuestas fueron geniales, muy precisas y útiles! No sé cuál aceptar - Creo que es la manera más justa de aceptar la "primera" respuesta?

Acepté la respuesta de blindmeis, ya que resolvió el problema y me ayudó a entender MVVM mejor. ¡Pero cada respuesta fue realmente genial gracias a todos ustedes!

+1

modelo de vista debería tener ninguna referencia a una visión/control de usuario. por lo que debe eliminar esto de su modelo de vista. este es un buen punto de partida: http://msdn.microsoft.com/en-us/magazine/dd419663.aspx – blindmeis

Respuesta

6

si quieres hacer mvvm - entonces deberías tener sin referencias para ver/usercontrols en tu viewmodel. tiene que implementar INotifyPropertyChanged! ps: si necesita el espacio de nombres System.Windows en su Viewmodel, entonces algo está mal.

en su caso lo que necesita:

  • 1 mainviewmodel
  • 1 viewmodel para UserControlMouse
  • 1 viewmodel para UserControlTouch
  • 1 view/usercontrol para UserControlMouse
  • 1 view/usercontrol de UserControlTouch

su mainviewmodel debe tener al menos 2 comandos para cambiar su vista y 1 propiedad para CurrentView. en su comando simplemente configura su CurrentView en la instancia de viewmodel derecha. al menos necesita dos plantillas de datos para cada modelo de vista que define la vista correcta.

public object CurrentView 
{ 
    get { return _currentView; } 
    set { 
     _currentView = value; this.RaiseNotifyPropertyChanged("CurrentView");} 
} 

xaml

<Window x:Class="WpfTestApplication.MainWindow" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
xmlns:local="clr-namespace:WpfTestApplication" 
Title="MainWindow" Height="350" Width="525"> 
<Window.Resources> 
<DataTemplate DataType="{x:Type local:MyMouseViewModel}"> 
    <local:MyMouseUserControlView/> 
    </DataTemplate> 
<DataTemplate DataType="{x:Type local:MyTouchViewModel}"> 
    <local:MyTouchUserControlView/> 
    </DataTemplate> 
</Window.Resources> 
<Window.DataContext> 
<local:MainWindowViewModel /> 
</Window.DataContext> 
<Grid> 

<!-- here your buttons with command binding, i'm too lazy to write this. --> 

<!-- you content control --> 
<ContentControl Content="{Binding CurrentView, Mode=OneWay}" /> 
</Grid> 
</Window> 
+0

Esto es mucha ayuda e información para mi progreso de aprendizaje. Empecé ayer con WPF/MVVM, por lo que ya estaba bastante contento de que ICommand-Behavior funcione;) – basti

+0

Si desea MVVM puro, la vista tampoco debería tener referencias al modelo de vista. Cree una instancia de la vista y vea el modelo en el inicio de la aplicación y vincule el modelo de vista al contexto de datos en su método de inicio. –

+0

+1 para "si necesita espacio de nombres System.Windows en su Viewmodel - entonces algo está mal". Estoy totalmente de acuerdo con eso; desafortunadamente, muchos artículos y marcos de MVVM recomiendan derivar comandos de 'ICommand' que introduce una dependencia innecesaria de los ensamblajes de WPF en ViewModel. –

2

El modelo de vista debe implementar INotifyPropertyChanged. De lo contrario, la vista no se notificará cuando una propiedad cambie en el modelo de vista.

class MainWindowViewModel : INotifyPropertyChanged 
{ 
    private UserControl _currentView = new DecisionMaker(); 

    public UserControl CurrentView 
    { 
     get { return _currentView; } 
     set 
     { 
      _currentView = value; 
      OnPropertyChanged("CurrentView"); 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
    private void OnPropertyChanged(string propertyName) 
    { 
     if (PropertyChanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
} 
+0

Gracias, ya lo implementé (después de su respuesta) y funciona muy bien. Pero, ¿por qué lo necesito aquí y no para las propiedades de tipo String? – basti

+1

esto funciona para su caso, pero no es mvvm – blindmeis

1

es necesario implementar INotifyPropertyChanged en MainWindowViewModel, de modo que la vista es informado cuando se cambia la propiedad CurrentView.

3

Haría algo como esto para seleccionar el estilo de entrada que desea, a MainWindow agregué una propiedad que me permite seleccionar el modo de entrada.

public enum UserInterfaceModes 
{ 
    Mouse, 
    Touch, 
} 

public UserInterfaceModes UserInterfaceMode 
{ 
    get { return (UserInterfaceModes)GetValue(UserInterfaceModeProperty); } 
    set { SetValue(UserInterfaceModeProperty, value); } 
} 

public static readonly DependencyProperty UserInterfaceModeProperty = DependencyProperty.Register("UserInterfaceMode", typeof(UserInterfaceModes), typeof(MainWindow), new UIPropertyMetadata(UserInterfaceModes.Mouse)); 

para la parte de vista xaml puede seleccionar la plantilla correcta con un disparador.

<Style TargetType="{x:Type local:MainWindow}"> 
    <Style.Triggers> 
     <DataTrigger Binding="{Binding UserInterfaceMode}" Value="Mouse"> 
      <Setter Property="Template"> 
        <Setter.Value> 
         <ControlTemplate TargetType="{x:Type local:MainWindow}"> 
          <Grid Background="Red"/> 
         </ControlTemplate> 
        </Setter.Value> 
      </Setter> 
     </DataTrigger> 
     <DataTrigger Binding="{Binding UserInterfaceMode}" Value="Touch"> 
      <Setter Property="Template"> 
        <Setter.Value> 
         <ControlTemplate TargetType="{x:Type local:MainWindow}"> 
          <Grid Background="Blue"/> 
         </ControlTemplate> 
        </Setter.Value> 
       </Setter> 
     </DataTrigger> 
    </Style.Triggers> 
</Style> 
+0

Definitivamente una gran respuesta, ¡eso me ayudará en el futuro! Para este problema específico que estoy enfrentando ahora para probar/aprender, no es 100% aplicable, ya que negará todo el diseño de los botones;) ¡Pero en futuras implementaciones 'reales', seguro volveré por su código! – basti

+0

¡Aww, me harás sonrojar! : D – Andy

1

Suena como el comportamiento que desea es más o menos lo que se obtiene con un [TabControl][1] - por qué no usar esta construido en el control y simplemente se unen al DataContext de ambas pestañas para el mismo modelo de vista.

Esto también tiene la ventaja de que su modelo de vista no sabría sobre las clases de vista (supongo que UserControlMouse etc. son controles de usuario).

Nota: esto no será aplicable si necesita que el modelo de vista esté al tanto de si está en modo táctil o de mouse.

+0

Gracias. Ese es el objetivo general aquí, dividir el UserControl en Mouse y TouchMode. Entonces, una vez en el inicio necesitaré "conocer" los controles de inicio de usuario. – basti

+0

@chiffre aún no debería hacer referencia a los componentes de vista (controles de usuario) en el modelo de vista si quiere hacer MVVM –

+0

. Creo que seguiré la respuesta de blindmeis para futuros trabajos sobre ella. ¡Gracias por tu gran ayuda en este caso! – basti

Cuestiones relacionadas