Hallo zusammen,
ich könnte mal wieder Hilfe bei der (sinnvollen) Implementierung von MVVM brauchen. Grundsätzlich bin ich mit der Thematik halbwegs vertraut, aber ab und zu hänge ich dann doch mal. Jetzt gerade möchte ich zum Beispiel eine Desktopanwendung entwickeln, die ein RibbonControl mit zunächst zwei Tabs enthält. Ich möchte, dass wenn ich die Tabs wechsle auch die View unterhalb des RibbonControls wechselt. Dazu bin ich bislang so vorgegangen:
Zunächst Views und ViewModels erstellt: Es gibt drei Views mit jeweils einem ViewModel. MainView und MainViewModel, TimeTableView und TimeTableViewModel, AnalysisView und AnalysisViewModel. Die MainView beschreibt das Hauptfenster und enthält das RibbonControl und einen ContentPresenter zum Anzeigen der anderen beiden Views:
Das dazugehörige ViewModel "MainViewModel":
Die einzelnen Views "TimeTableView.xaml" und "AnalysisView.xaml" sind jeweils UserControls. In beiden Fällen setze ich deren DataContext im Xaml auf das jeweilige ViewModel, z.B für die AnalysisView:
Die Idee dahinter ist dass ich die IsSelected-Eigenschaft der einzelnen Tabs an ein eigenes Property im MainViewModel binde. Je nachdem wird dann die im Konstruktor erzeugte ViewModel-Instanz des passenden ViewModels an ActiveViewModel übergeben, die wiederum an den Content des ContentPresenter gebunden ist. Durch die DataTemplates in den Ressources des MainWindow weiß dann der ContentPresenter anhand des ViewModel Types wie ActiveViewModel dargestellt werden soll. (So funktioniert es in meinem Kopf)
Das Wechseln der Views beim Wechseln des Tabs funktioniert auch soweit. Allerdings stört mich, dass bei jedem Wechsel wieder eine neue Instanz des jeweiligen ViewModels erzeugt wird (Sub New() des ViewModels wird aufgerufen). Daher dachte ich ich instanziiere ich jeweils eine Instanz im Konstruktor der MeinViewModel-Klasse und übergebe immer diese Instanzen an AvtiveViewModel. Das löst das Problem allerdings nicht, vermutlich weil im DataContext der einzelnen Views nochmal auf das ViewModel verwiesen wird. Gibt es dafür eine Lösung oder einen besseren Weg das Ganze umzusetzen?
Viele Grüße
Andy
ich könnte mal wieder Hilfe bei der (sinnvollen) Implementierung von MVVM brauchen. Grundsätzlich bin ich mit der Thematik halbwegs vertraut, aber ab und zu hänge ich dann doch mal. Jetzt gerade möchte ich zum Beispiel eine Desktopanwendung entwickeln, die ein RibbonControl mit zunächst zwei Tabs enthält. Ich möchte, dass wenn ich die Tabs wechsle auch die View unterhalb des RibbonControls wechselt. Dazu bin ich bislang so vorgegangen:
Zunächst Views und ViewModels erstellt: Es gibt drei Views mit jeweils einem ViewModel. MainView und MainViewModel, TimeTableView und TimeTableViewModel, AnalysisView und AnalysisViewModel. Die MainView beschreibt das Hauptfenster und enthält das RibbonControl und einen ContentPresenter zum Anzeigen der anderen beiden Views:
XML-Quellcode
- <Window x:Class="MainWindow"
- xmlns...>
- <Window.Resources>
- <DataTemplate DataType="{x:Type local:TimeTableViewModel}">
- <local:TimeTableView/>
- </DataTemplate>
- <DataTemplate DataType="{x:Type local:AnalysisViewModel}">
- <local:AnalysisView/>
- </DataTemplate>
- </Window.Resources>
- <Window.DataContext>
- <local:MainViewModel x:Name="vmMainWindow" />
- </Window.DataContext>
- <Grid>
- <Grid.RowDefinitions >
- ...
- </Grid.RowDefinitions>
- <Ribbon Grid.Row="0">
- <Ribbon.ApplicationMenu>
- <RibbonApplicationMenu LargeImageSource=...>
- <RibbonApplicationMenuItem Header="Options" ImageSource=.../>
- <RibbonApplicationMenuItem Header="Exit" ImageSource=.../>
- </RibbonApplicationMenu>
- </Ribbon.ApplicationMenu>
- <RibbonTab Header="Time Table" IsSelected="{Binding TimeTableTabActive}">
- <RibbonGroup Header="Live">
- <RibbonMenuButton Label="Start" LargeImageSource=.../>
- <RibbonButton Label="Source" SmallImageSource=.../>
- <RibbonButton Label="Refresh" SmallImageSource=... />
- </RibbonGroup>
- <RibbonGroup Header="Post session" Foreground="Black">
- <RibbonButton Label="CSV" LargeImageSource=.../>
- <RibbonButton Label="Clear" SmallImageSource=.../>
- </RibbonGroup>
- <RibbonGroup Header="Database" Foreground="Black">
- <RibbonButton Label="Connect" LargeImageSource=.../>
- <RibbonButton Label="Disconnect" SmallImageSource=.../>
- </RibbonGroup>
- </RibbonTab>
- <RibbonTab Header="Analysis" IsSelected="{Binding AnalysisTabActive}">
- <RibbonGroup Header="Plot">
- ...
- </RibbonGroup>
- </RibbonTab>
- </Ribbon>
- <ContentControl Grid.Row="1" Content="{Binding ActiveViewModel, Mode=OneWay}">
- </ContentControl>
- </Grid>
- </Window>
Das dazugehörige ViewModel "MainViewModel":
VB.NET-Quellcode
- Public Class MainViewModel : Inherits BindableBase
- Dim _TimeTableTabActive As Boolean
- Dim _AnalysisTabActive As Boolean
- Dim _TimeTable AsTimeTableViewModel
- Dim _Analysis As AnalysisViewModel
- Dim _activeViewModel As Object
- Public Property ActiveViewModel As Object
- Get
- Return _activeViewModel
- End Get
- Set(value As Object)
- _activeViewModel = value
- NotifyPropertyChanged()
- End Set
- End Property
- Public Property TimeTableTabActive As Boolean
- Get
- Return _TimeTableTabActive
- End Get
- Set(value As Boolean)
- _TimeTableTabActive = value
- If _TimeTableTabActive Then
- Me.ActiveViewModel = TimeTable
- End If
- NotifyPropertyChanged()
- End Set
- End Property
- Public Property AnalysisTabActive As Boolean
- Get
- Return _AnalysisTabActive
- End Get
- Set(value As Boolean)
- _AnalysisTabActive = value
- If AnalysisTabActive Then
- Me.ActiveViewModel = Analysis
- End If
- NotifyPropertyChanged()
- End Set
- End Property
- Public Property TimeTable As TimeTableViewModel
- Get
- Return _TimeTable
- End Get
- Set(value As TimeTableViewModel)
- _TimeTable = value
- NotifyPropertyChanged()
- End Set
- End Property
- Public Property Analysis As AnalysisViewModel
- Get
- Return _Analysis
- End Get
- Set(value As AnalysisViewModel)
- _Strategy = value
- NotifyPropertyChanged()
- End Set
- End Property
- Public Sub New()
- ...
- TimeTable = New TimeTableViewModel()
- Analysis = New AnalysisViewModel()
- TimeTabaleTabActive = False
- AnalysisTabActive = True
- Me.ActiveViewModel = Analysis
- End Sub
- End Class
Die einzelnen Views "TimeTableView.xaml" und "AnalysisView.xaml" sind jeweils UserControls. In beiden Fällen setze ich deren DataContext im Xaml auf das jeweilige ViewModel, z.B für die AnalysisView:
Die Idee dahinter ist dass ich die IsSelected-Eigenschaft der einzelnen Tabs an ein eigenes Property im MainViewModel binde. Je nachdem wird dann die im Konstruktor erzeugte ViewModel-Instanz des passenden ViewModels an ActiveViewModel übergeben, die wiederum an den Content des ContentPresenter gebunden ist. Durch die DataTemplates in den Ressources des MainWindow weiß dann der ContentPresenter anhand des ViewModel Types wie ActiveViewModel dargestellt werden soll. (So funktioniert es in meinem Kopf)
Das Wechseln der Views beim Wechseln des Tabs funktioniert auch soweit. Allerdings stört mich, dass bei jedem Wechsel wieder eine neue Instanz des jeweiligen ViewModels erzeugt wird (Sub New() des ViewModels wird aufgerufen). Daher dachte ich ich instanziiere ich jeweils eine Instanz im Konstruktor der MeinViewModel-Klasse und übergebe immer diese Instanzen an AvtiveViewModel. Das löst das Problem allerdings nicht, vermutlich weil im DataContext der einzelnen Views nochmal auf das ViewModel verwiesen wird. Gibt es dafür eine Lösung oder einen besseren Weg das Ganze umzusetzen?
Viele Grüße
Andy