2016-05-16 12 views
0

Ich versuche, MVVM in den Kopf zu bekommen, ich bin derzeit fest, wie man mit der Navigation umgehen soll.Navigation mit Rahmen und Combobox MVVM

Derzeit habe ich eine Seite und innerhalb dieser Seite ist ein Rahmen, dieser Rahmen ist verantwortlich für das Framing in verschiedenen anderen Seiten. Die Navigation wurde zuvor mit einer Dropdown-Box gehandhabt und bei einer Änderung wurde sie auf diese Weise navigiert.

Ich bin mir nicht sicher, wie ich das tun könnte, ohne den Rahmen aus der Modellansicht zu berühren, was am Schluss den mvvm zerstören würde.

Am Ende, was ich versuche zu erreichen ist, klicken Sie auf die Combobox, wählen Sie ein Element und dann Rahmen unten navigieren Sie zur richtigen Ansicht.

Ich verwende kein Prism oder irgendein anderes Framework mit MVVM, versuche nur, alles manuell zu machen.

Antwort

1

Die ComboBox würde eine ObservableCollection der Frame-Elemente von Ihrem Hauptansichtsmodell ausgestellt anzeigen, und das Viewmodel wird eine andere Eigenschaft für das ausgewählte Element haben.

Ihr ViewModel und die Frame-ViewModels erben alle von einer ViewModelBase-Klasse, die INotifyPropertyChanged implementiert, und vielleicht ein paar andere Sachen.

So, C#:

public ObservableCollection<ViewModelBase> FrameItems { get; protected set; } 

private ViewModelBase _selectedFrameItem; 
public ViewModelBase SelectedFrameItem { 
    get { return _selectedFrameItem; } 
    set { 
     value = _selectedFrameItem; 
     // Defined in ViewModelBase 
     OnPropertyChanged(); 
    } 
} 

Ihr Hauptansichtsmodell wird FrameItems in seinem Konstruktor füllen:

public MainViewModel() 
{ 
    FrameItems = new ObservableCollection<ViewModelbase> { 
     new IceCreamMenu(), 
     new SmurfOptions(), 
     new MagicSparklePonyFourierTransformConfiguration() 
    }; 
} 

Jeder Frame Artikel ist eine Unterklasse von ViewModelBase. Es macht Eigenschaften mit Benachrichtigungen verfügbar, einschließlich ObservableCollections eines beliebigen Satzes von untergeordneten Dingen, die es möglicherweise hat. Und wir werden es anzeigen, indem wir ein Datamaplate dafür in ein bisschen schreiben.

Nehmen wir an, Sie haben Ihrer ViewModelBase Klasse eine String Title { get; set; } Eigenschaft gegeben. Oder vielleicht möchten Sie eine Unterklasse von ViewModelBase schreiben, die Title einführt; Ihr Anruf. Für jetzt lassen Sie uns es zur Einfachheit in ViewModelBase setzen.

XAML - das lässt das Layout aus, aber Sie brauchen das hier nicht.

<ComboBox 
    ItemsSource="{Binding FrameItems}" 
    SelectedItem="{Binding SelectedFrameItem}" 
    DisplayMemberPath="Title" 
    /> 

<Frame Content={Binding SelectedFrameItem}" /> 

in Ordnung, aber wie auf der Erde weiß, ist das, was mit SelectedFrameItem zu tun?

Einfach! Schreiben Sie ein Ressourcenwörterbuch mit dem Namen, sagen wir ViewModelDataTemplates.xaml, und verschmelzen Sie es in App.xaml, so dass der Inhalt in jedem XAML in Ihrer Anwendung "sichtbar" ist.

App.xaml

<Application.Resources> 
    <ResourceDictionary> 
     <ResourceDictionary.MergedDictionaries> 
      <!-- Source is a relative path from project root directory --> 
      <ResourceDictionary Source="ViewModelDataTemplates.xaml" /> 
     </ResourceDictionary.MergedDictionaries> 
    </ResourceDictionary> 
</Application.Resources> 

... plus was auch immer Thema Sachen oder was auch immer.

Definieren Sie in ViewModelDataTemplates.xaml Datenvorlagen für Ihre Rahmenelementklassen.

Sagen Sie bitte ein IceCreamMenu Ansichtsmodell haben, mit einer Sammlung von Flavors

public ObservableCollection<IceCreamFlavor> Flavors { get; protected set; } 

... und SelectedFlavor. Sie würden den Namespace vm entsprechend mit einem xmlns:vm-Attribut im Ressourcenwörterbuch definieren.

ViewModelDataTemplates.xaml

<DataTemplate DataType="{x:Type vm:IceCreamMenu}"> 
    <Grid> 
     <ListBox 
      ItemsSource="{Binding Flavors}" 
      SelectedItem="{Binding SelectedFlavor}" 
      /> 
    </Grid> 
</DataTemplate> 

<DataTemplate DataType="{x:Type vm:IceCreamFlavor}"> 
    <StackPanel Orientation="Horizontal"> 
     <Border 
      Height="20" 
      Width="20" 
      Margin="4" 
      Background={Binding Color, Converter={StaticResource ColorToBrushConverter}}" 
      /> 
     <Label Content="Name" /> 
    </StackPanel> 
</DataTemplate> 

Wenn Sie UserControls vorhandene haben, die Sie über Datatemplates verwenden möchten, das ist einfach: Sagen Sie bitte eine NotesTabViewUserControl haben, die einen Blick für Ihren NotesTabViewModel ist, könnten Sie definieren ein Datatemplate wie folgt aus:

<DataTemplate DataType="{x:Type vm:NotesTabViewModel}"> 
    <vw:NotesTabView /> 
</DataTemplate> 
+0

Wenn ich dies tue, wähle ich ein Element aus dem Kombinationsfeld, es ändert den Inhalt des Rahmens zu nur dem Namen des Ansichtsmodells, das es instanziiert, als wenn es nur eine .tostring() -Methode darauf macht. Die gesamte DataTemplate definiert, wie die Daten korrekt angezeigt werden? Nun die Sache, wenn ich eine separate Ansicht für jede Seite bereits erstellt haben, so dass es nur in die richtige Ansicht wechseln muss – Tbooty

+0

Klingt, als ob es die Datatemplate für den Viewmodel Typ nicht finden Sie in den Rahmen. Verschmelzen Sie Ihre datatemplates.xaml in App.xaml? –

+0

@Tbooty App.xaml zu meiner Antwort hinzugefügt –

0

@EdPlunkett: Als Alternative zu Datatemplate für jede Ansicht, können Sie Ihren Rahmen an ausgewählte Seite binden Viewmodel mit ViewModelToViewConverter wie ich hier: https://stackoverflow.com/a/31721236/475727

Implizite DataTemplates und DataTemplateSelectors sind einzigartig für WPF und XAML, also denken Leute, dass es eine empfohlene Lösung ist, aber ich denke, dass es nicht für die Navigation geeignet ist. Es fühlt sich häschen an und es riecht nach Verletzung des DRY-Prinzips.

+0

Danke, ich schaue mir das an. Natürlich bedeutet das eine Art IoC-Setup. –

+0

Aber ja, wenn implizite Vorlagen nur auf WPF funktionieren, sind sie anderswo keine gute Lösung! –