Home > Blockchain >  Handling Events in MVVM
Handling Events in MVVM

Time:03-22

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

  • Related