2014-10-08 9 views
5

Ich habe mich entschieden, die MVVM Light-Bibliothek zu verwenden, um beim Entwurf einer Benutzeroberfläche zu helfen. Nach vielen Recherchen und Versuchen habe ich noch nicht die Antworten gefunden, nach denen ich suche. Ich habe gegoogelt und jede StackOverflow Frage gelesen, die ich finden kann, aber mein Problem scheint auf SO einzigartig zu sein.MVVM Light - Benutzersteuerelemente als Ansichten

Ich möchte eine Benutzeroberfläche mit einem einzigen Fenster entwerfen und es mit verschiedenen Ansichten/UserControls füllen. Ich möchte keine geteilte Navigationsleiste unter den Benutzersteuerelementen, noch möchte ich mehrere Fenster Pop-up-Fenster. Jedes View/UserControl sollte an sein eigenes ViewModel binden, während das MainWindow an ein MainViewModel bindet.

Beispielszenario - Mainwindow mit 3 Usercontrols

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. 

Oder

zusätzlich
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. 

usw. usw.

Vielleicht ist mein Ansatz ist nicht realistisch, aber ich fühle mich dies muss möglich sein. Ich verstehe nicht, wie all diese Stücke konzeptionell funktionieren. Es gibt keine Möglichkeit, dass meine Wünsche einzigartig sind. Wenn Sie der Meinung sind, dass dies eine doppelte Frage ist, leiten Sie sie bitte weiter. Prost.


Um die Dinge verständlicher zu machen, habe ich unten einige Klassen eingefügt. Zuerst meine 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> 

Wenn etwas unklar ist, kann ich die Modellklassen als auch hinzufügen, aber ich nehme an, Sie Schlüsse aus machen können, was los ist. Vielen Dank.

Antwort

3

So ist Ihr Ansatz sehr plausibel.Es gibt einige Komplikationen, die Sie verwenden müssen, um diese Funktionalität zu erhalten . Ich musste ein "MainViewModel" verwenden, das alle Ansichtsmodelle enthielt. Diese Ansichtsmodelle verhalten sich so, dass, wenn der Datenkontext zu einem anderen Ansichtsmodell wechselt, das entsprechende Benutzersteuerelement zu der entsprechenden Ansicht wechseln würde. Ein gutes Beispiel, dem ich folgte, wurde von Sheridan here beantwortet. Hook in Ihre app.xaml mit den entsprechenden Datenvorlagen und Datenkontext-Schalter werden wie magisch gehandhabt: D

Wo ich von Sheridan Beispiel divergierte (weil ich nicht eine separate Relaisbefehl Klasse/Objekt erstellen wollte), Ich habe tatsächlich mvvm light (galasoft) verwendet, um Nachrichten von meinen Viewmodels an eine Nachricht zurück an das "MainViewModel" zu senden, um seinen Datenkontext zu wechseln. Ein gutes Beispiel für die Verwendung von MVVM Light Messaging ist here. Senden Sie die Nachricht aus dem "untergeordneten" Ansichtsmodell, und registrieren Sie es im "MainViewModel".

Viel Glück!

+0

Ich habe meine App.xaml genau wie das erste von Ihnen erwähnte Beispiel angelegt. Anstatt meine ViewModels von BaseViewModel abzuleiten, leite ich von ViewModelBase von MVVM Light ab. Ich bin ein bisschen auf Messenger verloren. Morgen werde ich all meine Klassen veröffentlichen, um sie zu sehen. – piofusco

+0

Okay! Sie haben mich ein wenig daran verloren, wie Sie Ihre ViewModelBase von MVVM Light ableiten. Aber poste doch mal deinen Code und ich schaue nach. – Stunna

+0

Neuer Code oben hinzugefügt. – piofusco

1

Können Sie nicht eine Schnittstelle für Beispiel IChildLayout verwenden? Jedes Ansichtsmodell dieser Schnittstelle erben ...

public interface IChildLayout:INotifyPropertyChanged 
{ 
    public MainWindows_ViewModel Parent; 
} 

In Ihrem MainWindows Ansichtsmodell Sie so etwas wie dieses ...

Eine Eigenschaft IChildLayout, die, wenn Sie auf Ihre Tasten ... Klicken Sie auf Änderungen haben

Für jedes Layout können Sie das übergeordnete Fenster ViewModel abrufen (es ist wichtig, das Layout zu ändern, indem Sie die Eigenschaft "Child" aus dem eigenen ViewModel bearbeiten ...)

Sie setzen ein UserControl innerhalb Ihrer Hauptfenster (in der XAML), der Inhalt wird an Ihre Child-Eigenschaft gebunden, dann wird es jedes Mal aktualisiert, wenn Sie Ihre Child-Eigenschaft ändern.

<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 diesem Fall können Sie Ihre First_ViewModel sein: (In diesem Beispiel I Prisma DelegateCommand verwenden Button-Aktionen zu binden ...

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... 

}

Ich hoffe, dies wird Ihnen helfen Ich habe so etwas getan, um verschiedene Tab in einer WPF-Anwendung zu verwalten

+0

Das sieht logisch gut aus, also werde ich mein Bestes versuchen, damit das funktioniert. Alle weiteren Codebeispiele wären willkommen. Vielen Dank. – piofusco