2014-10-08 15 views
5

Ho deciso di utilizzare la libreria MVVM Light per aiutare a progettare un'interfaccia utente. Dopo tonnellate di ricerche e tentativi ed errori, devo ancora trovare le risposte che sto cercando. Ho cercato su Google e letto ogni domanda StackOverflow che riesco a trovare, tuttavia, il mio problema sembra essere unico su SO.MVVM Light - Controlli utente come viste

Desidero progettare un'interfaccia utente con una singola finestra e popolarla con diversi Views/UserControls. NON voglio una barra di navigazione condivisa tra gli UserControls né voglio che vengano visualizzate più finestre. Ogni View/UserControl dovrebbe collegarsi al proprio ViewModel, mentre MainWindow si collegherà a un MainViewModel.

Scenario di esempio - MainWindow con 3 controlli utente

1. MainWindow populates with first UserControl which has a listbox and 3 buttons, the first button is enabled. 
2. User clicks the first button. 
3. MainWindow populates with second UserControl. 

Oppure, in aggiunta

2. User selects choice from a listbox, button two and three become available. 
3. User clicks second/third button. 
4. MainWindow populates with second/third UserControl. 

Ecc, ecc

Forse il mio approccio non è realistico, ma mi sento questo deve Essere possibile. Non capisco come far funzionare tutti questi pezzi concettualmente. Non c'è modo in cui i miei desideri siano unici. Se ritieni che si tratti di una domanda doppia, reindirizza. Saluti.


Per rendere le cose più facili da capire, ho incluso alcune classi di seguito. Innanzitutto, la mia app.xaml.

<Application x:Class="Bobcat_BETA.App" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:views="clr-namespace:Bobcat_BETA.UserControls" 
      xmlns:vm="clr-namespace:Bobcat_BETA.ViewModels" 
      StartupUri="MainWindow.xaml" 
      mc:Ignorable="d"> 
    <Application.Resources> 
     <vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" /> 

     <DataTemplate DataType="{x:Type vm:SavedScenariosViewModel}"> 
      <views:SavedScenariosUserControl /> 
     </DataTemplate> 
     <DataTemplate DataType="{x:Type vm:ScenarioEditorViewModel}"> 
      <views:ScenarioEditorUserControl /> 
     </DataTemplate> 
     <DataTemplate DataType="{x:Type vm:SimulatorViewModel}"> 
      <views:SimulatorUserControl /> 
     </DataTemplate> 

    </Application.Resources> 
</Application> 

MainWindow.xaml

<Window x:Class="Bobcat_BETA.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="Bobcat - Version:0.00" 
    DataContext="{Binding Main, Source={StaticResource Locator}}"> 
<Grid> 
    <ContentControl Content="{Binding CurrentView}"/> 
</Grid> 

ViewModelLocator.cs

namespace Bobcat_BETA.ViewModels 
{ 

    public class ViewModelLocator 
    { 

     private static MainViewModel _main; 

     public ViewModelLocator() 
     { 
      _main = new MainViewModel(); 
     } 

     [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", 
      "CA1822:MarkMembersAsStatic", 
      Justification = "This non-static member is needed for data binding purposes.")] 
     public MainViewModel Main 
     { 
      get 
      { 
       return _main; 
      } 
     } 
    } 
} 

MainViewModel.cs

namespace Bobcat_BETA.ViewModels 
{ 
    public class MainViewModel : ViewModelBase 
    { 
     private ViewModelBase _currentViewModel; 

     readonly static SavedScenariosViewModel _savedScenarioViewModel = new SavedScenariosViewModel(); 
     readonly static ScenarioEditorViewModel _scenarioEditorViewModel = new ScenarioEditorViewModel(); 
     readonly static SimulatorViewModel _simulatorViewModel = new SimulatorViewModel(); 

     public ViewModelBase CurrentViewModel 
     { 
      get 
      { 
       return _currentViewModel; 
      } 
      set 
      { 
       if (_currentViewModel == value) 
        return; 
       _currentViewModel = value; 
       RaisePropertyChanged("CurrentViewModel"); 
      } 
     } 

     public MainViewModel() 
     { 
      CurrentViewModel = MainViewModel._savedScenarioViewModel; 
      SavedScenarioViewCommand = new RelayCommand(() => ExecuteSavedScenarioViewCommand()); 
      ScenarioEditorViewCommand = new RelayCommand(() => ExecuteScenarioEidtorViewCommand()); 
      SimulatorViewCommand = new RelayCommand(() => ExecuteSimulatorViewCommand()); 
     } 

     public ICommand SavedScenarioViewCommand { get; private set; } 
     public ICommand ScenarioEditorViewCommand { get; private set; } 
     public ICommand SimulatorViewCommand { get; private set; } 

     private void ExecuteSavedScenarioViewCommand() 
     { 
      CurrentViewModel = MainViewModel._savedScenarioViewModel; 
     } 

     private void ExecuteScenarioEidtorViewCommand() 
     { 
      CurrentViewModel = MainViewModel._scenarioEditorViewModel; 
     } 

     private void ExecuteSimulatorViewCommand() 
     { 
      CurrentViewModel = MainViewModel._simulatorViewModel; 
     } 
    } 
} 

SavedScenariosViewModel.cs

namespace Bobcat_BETA.ViewModels 
{ 
    public class SavedScenariosViewModel : ViewModelBase 
    { 

     public SavedScenariosViewModel() 
     { 
     } 

     ObservableCollection<ScenarioModel> _scenarioModels = new ObservableCollection<ScenarioModel>() 
     { 
      new ScenarioModel() {Name = "Scenario 0", ID = 000, Desc = "This will describe the Scenario Model."}, 
      new ScenarioModel() {Name = "Scenario 1", ID = 001, Desc = "This will describe the Scenario Model."}, 
      new ScenarioModel() {Name = "Scenario 2", ID = 002, Desc = "This will describe the Scenario Model."}, 
      new ScenarioModel() {Name = "Scenario 3", ID = 003, Desc = "This will describe the Scenario Model."}, 
      new ScenarioModel() {Name = "Scenario 4", ID = 004, Desc = "This will describe the Scenario Model."}, 
      new ScenarioModel() {Name = "Scenario 5", ID = 005, Desc = "This will describe the Scenario Model."}, 
      new ScenarioModel() {Name = "Scenario 6", ID = 006, Desc = "This will describe the Scenario Model."}, 
      new ScenarioModel() {Name = "Scenario 7", ID = 007, Desc = "This will describe the Scenario Model."}, 
      new ScenarioModel() {Name = "Scenario 8", ID = 008, Desc = "This will describe the Scenario Model."}, 
      new ScenarioModel() {Name = "Scenario 9", ID = 009, Desc = "This will describe the Scenario Model."} 
     }; 
     public ObservableCollection<ScenarioModel> ScenarioModels 
     { 
      get { return _scenarioModels; } 
     } 

    } 
} 

SavedScenariosUserControl.xaml

<UserControl x:Class="Bobcat_BETA.UserControls.SavedScenariosUserControl" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:vm="clr-namespace:Bobcat_BETA.ViewModels" 
      mc:Ignorable="d" 
      d:DesignHeight="300" d:DesignWidth="300"> 

    <UserControl.Resources> 
     <ResourceDictionary> 
      <ResourceDictionary.MergedDictionaries> 
       <ResourceDictionary Source="/Dictionaries/MasterDictionary.xaml" /> 
      </ResourceDictionary.MergedDictionaries> 
     </ResourceDictionary> 
    </UserControl.Resources> 

    <UserControl.Style> 
     <DynamicResource ResourceKey="GeneralUserControl"/> 
    </UserControl.Style> 

    <Grid> 
     <Label Content="Saved Scenario Selection" 
       Style="{StaticResource GeneralLabel}" HorizontalAlignment="Left" Margin="26,30,0,0" VerticalAlignment="Top" Height="62" Width="345"/> 
     <Label Content="Chose Flight Model:" 
       Style="{StaticResource GeneralLabel2}" 
       HorizontalAlignment="Left" Margin="27,111,0,0" VerticalAlignment="Top" Height="43" Width="345"/> 
     <ListBox Style="{StaticResource GeneralListBox}" 
       HorizontalAlignment="Left" Height="509" Margin="27,154,0,0" VerticalAlignment="Top" Width="345" 
       ItemsSource="{Binding ScenarioModels}"/> 

     <Button Content="New" 
       Style="{StaticResource TransitionButton}" 
       HorizontalAlignment="Left" Margin="948,601,0,0" VerticalAlignment="Top" MinHeight="62" MinWidth="150" IsEnabled="True" 
       Command="{Binding ScenarioEditorViewCommand}"/> 

     <Button Content="Edit" 
       Style="{StaticResource TransitionButton}" 
       HorizontalAlignment="Left" Margin="401,519,0,0" VerticalAlignment="Top" MinHeight="62" MinWidth="150" 
       Command="{Binding SaveScenariosViewCommand}"/> 
     <Button Content="Load" 
       Style="{StaticResource TransitionButton}" 
       HorizontalAlignment="Left" Margin="401,601,0,0" VerticalAlignment="Top" MinHeight="62" MinWidth="150" 
       Command="{Binding SimulatorViewCommand}"/> 

    </Grid> 
</UserControl> 

Se qualcosa non è chiaro, posso aggiungere le classi del modello pure, ma presumo si può fare inferenze da ciò che sta accadendo. Grazie.

risposta

3

Quindi il tuo approccio è molto plausibile.Ci sono alcune complicazioni che dovrai usare per ottenere quella funzionalità . Ho dovuto usare un "MainViewModel" che conteneva tutti i modelli di visualizzazione. Questi modelli di vista si comportano in modo tale che quando il contesto dei dati passava a un modello di visualizzazione diverso, il controllo utente corrispondente passava alla vista appropriata. Un buon esempio che ho seguito è stato risposto da Sheridan here. Collegati alla tua app.xaml con i modelli di dati appropriati e gli interruttori di contesto dati saranno gestiti come per magia: D

Dove mi sono allontanato dall'esempio di Sheridan (perché non volevo creare una classe/oggetto comando di inoltro separata), In realtà ho usato mvvm light (galasoft) per inviare messaggi dai miei viewmodels al messaggio di "MainViewModel" per cambiare il contesto dei dati. Un buon esempio di utilizzo di MVVM light può essere trovato here. Invia il messaggio dal modello di visualizzazione "figlio" e registralo in "MainViewModel".

Buona fortuna!

+0

In realtà ho la mia App.xaml presentata esattamente come il primo esempio che hai menzionato. Invece di ricavare i miei ViewModels da BaseViewModel, provengo da ViewModelBase di MVVM Light. Sono un po 'perso su Messenger però. Domani pubblicherò tutte le mie lezioni a cui tutti potranno dare un'occhiata. – piofusco

+0

Ok! Mi hai perso un po 'su come si ottiene ViewModelBase da MVVM Light. Ma sì, pubblica il tuo codice e darò un'occhiata. – Stunna

+0

Aggiunto un po 'di codice sopra. – piofusco

1

Non è possibile utilizzare un'interfaccia per esempio IChildLayout? Ogni ViewModel ereditano di questa interfaccia ...

public interface IChildLayout:INotifyPropertyChanged 
{ 
    public MainWindows_ViewModel Parent; 
} 

Nei tuoi MainWindows ViewModel si può avere qualcosa di simile ...

Una proprietà IChildLayout, che cambia quando si fa clic sui tasti ...

Per ogni layout è possibile recuperare la finestra padre ViewModel (è importante cambiare il layout modificando la proprietà "Figlio" dal proprio ViewModel ...)

Metti un UserControl all'interno delle tue finestre principali (nell'xaml), il contenuto è associato alla proprietà Figlio, quindi verrà aggiornato ogni volta che cambi la proprietà Figlio.

<Windows> 
    <Windows.DataContext> 
     <local:MainWindows_ViewModel/> 
    </Windows.DataContext> 
    <UserControl Content={Binding Child}> 
     <UserControl.Resources> 
      <DataTemplate DataType="{x:Type ViewModels:First_ViewModel}"> 
        <Controls:First_View DataContext="{Binding}"/> 
      </DataTemplate> 
      <DataTemplate DataType="{x:Type ViewModels:Second_ViewModel}"> 
        <Controls:Second_View DataContext="{Binding}" /> 
      </DataTemplate> 
     </UserControl.Resources> 
    </UserControl> 
</Windows> 

In questo caso, il vostro First_ViewModel può essere: (In questo esempio, io uso DelegateCommand prisma di legare le azioni dei pulsanti ...

public class First_ViewModel:IChildLayout 
{ 
public MainWindows_ViewModel Parent {get;set;} 

public ICommand cmdBtn1click{get;set;} 
private Pass_to_second_ViewModel() 
{ 
    //Here i change the Parent Child Property, it will switch to Second_View.xaml... 
    this.Parent.Child=new Second_ViewModel(); 
} 

public First_ViewModel() 
{ 
    // Here i connect the button to the command with Prism... 
    this.cmdBtn1click=new DelegateCommand(()=>Pass_to_second_ViewModel()); 

} 

#region INotifyPropertyChangedMembers... 

}

Spero che questo vi aiuterà , ho fatto questo genere di cose per gestire Tab diverse in un'applicazione WPF

+0

Questo sembra logicamente valido, quindi farò del mio meglio per farlo funzionare. Qualsiasi esempio di codice aggiuntivo sarebbe ben accetto. Grazie. – piofusco