Using Catel 3.9 and DevExpress 15.x
My Customer has asked that I make some UI changes to an app and I'm not sure it can easily be done.
Architecture:
- There is a MainWindow with an associated View and ViewModel.
- The MainWindow holds a TabControl where each Tab's content is a separate View/ViewModel. The MainWindow ViewModel does NOT own any of the nested VMs; they are constructed automatically by Catel at runtime by the View.
The old UI had buttons on each TabItem which allowed the Customer to load, save, display, filter, etc. The commands/properties for these buttons were bound directly to the ViewModel for that tab and was working fine.
The Customer would rather have a single top level (on the MainWindow) menu and selections from that menu would affect whichever tab had the current focus.
I can pass commands (using Messaging or Catel's InterestedIn attribute) to the correct ViewModel, but I'd like to have a more direct binding with the top level menu and the appropriate ViewModel so I can enable/disable menu items or even modify the text to suit whichever tab is open.
I'm looking for a primarily XAML and/or Catel solution. If you need additional information, please let me know.
Suggestions?
thanks, randy
Edit: Sorry that I didn't include additional research. If you knew me, you'd know I will spend hours/days looking for solutions to problems and only when I'm stumped will I ask for assistance. My bad for not including more.
The hardest part about this issue is defining good search parameters. Most of the suggestions were similar to: Just put everything into the MainWindow ViewModel which (to me) is not a good design choice because what is displayed on the tabs IS different and should be separate.
Other solutions were to have the MainWindow ViewModel construct each of the inner ViewModels and then manage them. With the Catel framework I'm using, the framework automatically constructs the VM when the View is loaded, injecting any required parameters to the constructor. See below -- you just reference the View and Catel will match it up with its ViewModel and create it for you. Unfortunately without taking other steps, you really don't have a reference to the VM that was created.
MainWindow.xaml:
<dx:DXTabControl x:Name="MainTabControl"
Grid.Row="1"
Margin="10"
BorderThickness="0"
SelectedIndex="{Binding SelectedTabIndex}"
>
<dx:DXTabItem Header="Getting Started" IsEnabled="True">
<views:GetStarted />
</dx:DXTabItem>
<dx:DXTabItem Header="Validate Student Records" Background="Ivory">
<views:StudentValidation />
</dx:DXTabItem>
<dx:DXTabItem Header="Validate Teacher Records" Background="Ivory">
<views:TeacherValidation />
</dx:DXTabItem>
<dx:DXTabItem Header="Validate Admin Records" Background="Ivory">
<views:AdminRecordValidation />
</dx:DXTabItem>
</dx:DXTabControl>
Examples of some possible solutions I'm looking at:
Edit #2: There was a suggestion about using a Service and SO doesn't allow you to add detailed comments (and it puts a TIMER on your comments -- SHEEESH!), so I'll put my response here.
Consider this scenario using a Service: The Customer starts the app and clicks on a Tab (StudentValidation). The MainWindowViewModel (via a Property) detects the selected tab and calls the Service with an update (I'm not sure what is updated; possibly some sort of State). The "nested" ViewModels are notified (via an Event) of the change in the Service. I'll assume the StudentValidationViewModel is the only one who actually responds to the event and interacts with the Service, retrieving "data".
So, now we have the StudentValidation tab displayed and the Customer goes to the Main Menu of the app. The Main Menu is STILL tied to the MainWindow and every command is bound to the MainWindowViewModel. How does the Service bind the Main Menu to the ViewModel of the currently selected tab so that the commands will be handled by the StudentValidationViewModel? I'm probably missing something.