So this is my first MVVM application. I have a "shell" view model named MainWindowViewModel for the main window that basically splits the view into two pages: MainWindowRibbon and MainWindowFrame. The MainWindowViewModel stores both pages as properties, which I plan to use databinding to update in the UI. Here is some of the code for reference:
MainWindowView xaml~
<Grid>
<Frame Content="{Binding MainWindowRibbon}" Grid.Column="0" Grid.Row="0"/>
<ScrollViewer>
<Frame Content="{Binding MainWindowFrame}"/>
</ScrollViewer>
</Grid>
MainWindowView code behind~
public partial class MainWindowView : Window
{
public MainWindowView()
{
InitializeComponent();
mainWindowViewModel = new MainWindowViewModel();
DataContext = mainWindowViewModel;
}
public MainWindowViewModel mainWindowViewModel;
}
MainWindowViewModel code~
public MainWindowViewModel()
{
//MainWindowRibbon and MainWindowFrame are declared as public Page properties
MainWindowRibbon = new MainWindowRibbonView();
MainWindowFrame = new WelcomePageView();
}
The MainWindowRibbonView, like the MainWindowView, instantiates the MainWindowRibbonViewModel.
My trouble comes when I wish to use an event within the MainWindowRibbonViewModel that will call for the MainWindowViewModel to reassign the MainWindowFrame page. I do not know how to connect the button command of the navigation bar I have created in the MainWindowRibbonView to cause an event or change in the MainWindowViewModel.
I do not know if the way I have organized this is ideal. Please let me know if I need to revise.
If somebody could help me determine the best approach, or even just a functioning one, I would be very grateful.
P.S. Sorry if the naming conventions aren't the greatest.
Edit: Lesson learned: listen to Joe.
CodePudding user response:
I suppose it depends on what kind of button you are using in your navigation bar. is it a RadioButton
? A RibbonToggleButton
? Is it a regular button binding to an ICommand
?
Since you called your Navigation Bar a "Ribbon", let us suppose it is a RibbonToggleButton
(which is still basically a CheckBox). If it is checked, you show some view-model your "page 1". If it is not checked, you should another view-model representing your "page 2"
Let us also suppose your view's ribbon is up top. So you have two rows: the Ribbon row and the content row.
I might rewrite your MainWindow to look like this, (note the IsChecked
property to some boolean property in your view-model like so:)
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/> <!-- The "Ribbon" -->
<RowDefinition Height="*"/> <!-- The page content -->
</Grid.RowDefinitions>
<ToggleButton Content="Show Page 1" IsChecked="{Binding ShowPage1}"/>
<ScrollViewer Grid.Row=1>
<Frame Content="{Binding CurrentViewModel}"/>
</ScrollViewer>
</Grid>
And I might write your view-model like this: (Note that I assume it implements INotifyPropertyChanged and I call a function RaisePropertyChanged
that I do not show.
public class Page1ViewModel {} // Fill this out with Page 1 properties
public class Page2ViewModel {} // Fill this out with Page 2 properties
// MainWindowViewModel. Implements INotifyPropertyChanged. Implementation
// is not shown here.
public class MainWindowViewModel : INotifyPropertyChanged
{
private Page1ViewModel = new Page1ViewModel();
private Page2ViewModel = new Page2ViewModel();
public MainWindowViewModel()
{
_currentViewModel = Page1ViewModel;
ShowPage1 = true;
}
private object _currentViewModel;
// The current contents of the main frame.
public object CurrentViewModel
{
get => _currentViewModel;
set
{
if (value == _currentViewModel)
return;
_currentViewModel = value;
RaisePropertyChanged();
}
// Should CurrentViewModel be page 1 or page 2?
public bool ShowPage1
{
get => return _currentViewModel == Page1ViewModel;
set
{
if (value == ShowPage1)
return;
CurrentViewModel = value ? Page1ViewModel : Page2ViewModel;
RaisePropertyChanged();
}
}
}
Note that I am not showing you any of the properties of Page1VieModel
or Page2ViewModel
nor have I shown you the implicit DataTemplate
s I assume you will write for them.
Also I am assuming that your navigation bar (and MainWindowView
in general) have a DataContext
that is already set to the MainWindowViewModel
The implemention with a command button or a RadioButton
would be quite different.