2012-06-12 19 views
6

Attualmente sto imparando WPF e MVVM (o almeno sto cercando di ...).Modifica visualizzazione su Buttonclick

Ho creato una piccola app di esempio, che mostra una finestra con 2 pulsanti, ognuno dei quali dovrebbe mostrare una nuova vista su clic. Così ho creato 3 UserControls (DecisonMaker con i 2 pulsanti e un Usercontrol per ogni "clicktarget").

Così ho legato la CotentControl del MainWindow ad una proprietà chiamata "CurrentView" nel mio MainWindowViewModel

Codice di 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> 

Codice di 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(); 
    } 
} 

L'iniziale UserControl (Decision Maker) si presenta come supposto. Viene anche chiamato il metodo LoadMouseView. Ma la vista non cambia. Cosa mi manca?

AGGIORNAMENTO: Grazie mille! Ho perso l'interfaccia INotifyPropertyChanged. Tutte le tue risposte sono state semplicemente fantastiche e molto accurate e utili! Non so quale accettare - Penso che sia il modo più giusto per accettare la "prima" risposta?

Ho accettato la risposta blindme, in quanto ha risolto il problema e mi ha aiutato a capire meglio MVVM. Ma ogni risposta è stata davvero grande, grazie a tutti voi!

+1

viewmodel dovrebbe avere alcun riferimento ad una vista/usercontrol. quindi dovresti rimuoverlo dal tuo viewmodel. questo è un buon punto di partenza: http://msdn.microsoft.com/en-us/magazine/dd419663.aspx – blindmeis

risposta

6

se vuoi fare mvvm - allora dovresti avere senza riferimenti alla tua vista/usercontrols nel tuo viewmodel. devi implementare InotifyPropertyChanged! ps: se hai bisogno dello spazio dei nomi System.Windows nel tuo Viewmodel - allora qualcosa non va.

nel tuo caso quello che vi serve:

  • 1 mainviewmodel
  • 1 ViewModel per UserControlMouse
  • 1 ViewModel per UserControlTouch
  • 1 visita/UserControl per UserControlMouse
  • 1 visita/UserControl per UserControlTouch

il tuo mainviewmodel dovrebbe avere almeno 2 comandi per cambiare visualizzazione e 1 proprietà per CurrentView. nel tuo comando devi semplicemente impostare il tuo CurrentView sulla giusta istanza di viewmodel. almeno hai bisogno di due datatemplates per ogni viewmodel che definiscono la vista giusta.

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

Questo è un sacco di aiuto e informazioni per i miei progressi di apprendimento. Ho appena iniziato ieri con WPF/MVVM, quindi ero già abbastanza contento di avere il funzionamento di ICommand;) – basti

+0

Se vuoi MVVM puro, la vista non dovrebbe avere riferimenti al modello di vista. Crea un'istanza della vista e visualizza il modello all'avvio dell'applicazione e associa il modello di visualizzazione al contesto dati nel metodo di avvio. –

+0

+1 per "se hai bisogno dello spazio dei nomi System.Windows nel tuo Viewmodel - allora qualcosa non va." Sono assolutamente d'accordo con questo; sfortunatamente, molti articoli e framework MVVM consigliano di derivare comandi da 'ICommand' che introduce una dipendenza non necessaria dagli assiemi WPF nel ViewModel. –

2

Il modello di visualizzazione deve implementare INotifyPropertyChanged. In caso contrario, la vista non verrà notificata quando una proprietà cambia in viewmodel.

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

Grazie ho già implementato questo (dopo la tua risposta) e funziona bene. Ma perché ne ho bisogno qui e non per le proprietà di tipo String? – basti

+1

questo funziona per il tuo caso, ma non è mvvm – blindmeis

1

è necessario implementare INotifyPropertyChanged su MainWindowViewModel, in modo tale che la vista è informato quando la proprietà CurrentView viene modificata.

3

Vorrei fare qualcosa del genere per selezionare lo stile di input che desideri, in MainWindow ho aggiunto una proprietà che mi consente di selezionare la modalità di input.

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)); 

quindi per la parte vista xaml è possibile selezionare il modello corretto con un trigger.

<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

Sicuramente una grande risposta, che mi aiuterà in futuro! Per questo problema specifico che sto affrontando ora per test/apprendimento, non è applicabile al 100% in quanto annullerà l'intero layout dei pulsanti;) Ma in futuro, in realizzazioni, sicuramente tornerò per il tuo codice! – basti

+0

Aww, mi fai arrossire! : D – Andy

1

Sembra che il comportamento desiderato è più o meno quello che si ottiene con un [TabControl][1] - perché non utilizzare questo costruito nel controllo e basta associare la DataContext di entrambe le schede per lo stesso modello di vista.

Questo ha anche il vantaggio che il tuo modello di vista non conoscerebbe le classi di vista (presumo che i controlli utente siano UserControlMouse ecc.).

Nota: questo non sarà applicabile se è necessario che il modello di visualizzazione sia consapevole della modalità touch o mouse.

+0

Grazie. Questo è l'obiettivo generale qui, per dividere l'UserControl in Mouse e TouchMode. Quindi una volta in fase di partenza avrò bisogno di "conoscere" i comandi start-us. – basti

+0

@chiffre non si dovrebbe ancora fare riferimento ai componenti di visualizzazione (controlli utente) nel modello di vista se si desidera eseguire MVVM –

+0

Penso che seguirò la risposta blindmeis per il lavoro futuro su di esso. Grazie per il tuo grande aiuto in questo caso! – basti

Problemi correlati