ViewModel - GetcuReone/MvvmFrame.Wpf GitHub Wiki

ViewModel

Another main part of the library. It contains a set of simple APIs to work with your view-models. The main in this part will be the class ViewModelBase. All your view-models should be inherited from it. A class is an inheritor of a class FactoryBase and has all its advantages.

Properties

NavigationManager

An instance of the class responsible for navigation between pages and view-models (common for models working with one frame)

UiServices

Service storage object. Stores information about UI services

Options

Settings for view-model behavior when changing properties

Methods

OnLoadPageAsync

Called when the page is drawn and ready to go (protected class method)

OnLeavePageAsync

Called when the page leaves the frame (protected class method)

OnGoPageAsync

Called when a page loads in a frame (protected class method)

OnErrors

Called if errors occurred while changing the class property

Initialize

Called before page initialization (protected class method)

SetPropertyValue

Property modifying method (protected class method)

GetModel

Returns the model attached to the current view-model

GetViewModel

Returns a view-model attached to the same frame as the current view-model

BindModel

Binds the model to the current view-model

Verification

The method is called when the property changes (do not call if Options.UseVerification is true)

Navigate

Starts navigation to the specified page

CreateViewModel

Creates a view-model attached to the specified frame.

How to use it?

We will need the experience from the example here

How to create a view-model and display a page?

  1. In the project, create a subfolder 'ViewModels'
  2. Create a class 'HomeViewModel' and inherit it from the class 'ViewModelBase'. Add property 'Title'
namespace Example_MvvmFrame.Wpf.ViewModels
{
    public class HomeViewModel: ViewModelBase
    {
        public string Title { get => _title; set => SetPropertyValue(ref _title, value); }
        private string _title = "Is Home page";
    }
}

I draw your attention, property values are set through a special Method 3. Change the layout of our page as follows

<Page
    x:Class="Example_MvvmFrame.Wpf.Pages.HomePage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="clr-namespace:Example_MvvmFrame.Wpf.Pages"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:view_models="clr-namespace:Example_MvvmFrame.Wpf.ViewModels"
    Title="HomePage"
    d:DataContext="{d:DesignInstance view_models:HomeViewModel,
                                     IsDesignTimeCreatable=True}"
    d:DesignHeight="450"
    d:DesignWidth="800"
    mc:Ignorable="d">

    <Grid Background="Azure">
        <StackPanel Orientation="Horizontal">
            <TextBlock FontSize="24" Text="{Binding Title}" />
        </StackPanel>
    </Grid>
</Page>
  1. Add the frame to the main window
<Window
    x:Class="Example_MvvmFrame.Wpf.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="clr-namespace:Example_MvvmFrame.Wpf"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="MainWindow"
    Width="800"
    Height="450"
    Loaded="Window_Loaded"
    mc:Ignorable="d">
    <Grid>
        <Frame x:Name="mainFrame" NavigationUIVisibility="Hidden" />
    </Grid>
</Window>
  1. Now we need to handle the loading of the window
namespace Example_MvvmFrame.Wpf
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            HomeViewModel homeViewModel = ViewModelBase.CreateViewModel<HomeViewModel>(mainFrame);
            ViewModelBase.Navigate<HomePage>(homeViewModel);
        }
    }
}

Now you can run the application and see

How does a property value change?

Take the previous example again.

  1. Add a textbox to the home page
<Grid Background="Azure">
        <StackPanel Orientation="Vertical">
            <TextBlock
                Margin="10"
                FontSize="24"
                Text="{Binding Title}" />
            <TextBox Margin="10" Text="{Binding Text}" />
            <TextBox Margin="10"/>
        </StackPanel>
    </Grid>
  1. In the HomeViewModel class, override the methods Verification and OnErrors
namespace Example_MvvmFrame.Wpf.ViewModels
{
    public class HomeViewModel: ViewModelBase
    {
        public string Title { get => _title; set => SetPropertyValue(ref _title, value); }
        private string _title = "Is Home page";

        public string Text { get => _text; set => SetPropertyValue(ref _text, value); }
        private string _text;

        public override string Verification(string propertyName)
        {
            switch (propertyName)
            {
                case nameof(Text):
                    if (Text.Last() == '+')
                        return "Can not use '+'";
                    break;
            }
            
            return base.Verification(propertyName);
        }

        public override void OnErrors(List<Func<string>> getErrorMessageList)
        {
            foreach (var getMessage in getErrorMessageList)
                MessageBox.Show(getMessage());
        }
    }
}

Each time the property changes, if the setting 'Options.UseVerification' is enabled, the method 'Verification' will be called. If an error message is returned when a property is changed, then you can process it in the method 'OnErrors'and also the property will return the previous value. This is not the end of the example, but you can already run and see. 5. Now let's subscribe to the property change event

    public class HomeViewModel: ViewModelBase
    {
        public string Title { get => _title; set => SetPropertyValue(ref _title, value); }
        private string _title = "Is Home page";

        public string Text { get => _text; set => SetPropertyValue(ref _text, value); }
        private string _text;

        public HomeViewModel()
        {
            VerifyPropertyChange += OnVerifyPropertyChange;
        }

        public override string Verification(string propertyName)
        {
            switch (propertyName)
            {
                case nameof(Text):
                    if (Text.Last() == '+')
                        return "Can not use '+' (Verification)";
                    break;
            }
            return base.Verification(propertyName);
        }

        public void OnVerifyPropertyChange(IModel model, MvvmElementPropertyVerifyChangeEventArgs args)
        {
            switch (args.PropertyName)
            {
                case nameof(Text):
                    if (Text.First() == '+')
                        args.AddError(() => "Can not use '+' (OnVerifyPropertyChange)");
                    break;
            }
        }

        public override void OnErrors(List<Func<string>> getErrorMessageList)
        {
            foreach (var getMessage in getErrorMessageList)
                MessageBox.Show(getMessage());
        }
    }
}

Our handler will work if the setting 'Options.UseVerifyPropertyChange' is enabled. Now this is the end of the example, you can run.

PS

  1. If the setting 'Options.UseOnlyOnPropertyChanged' is enabled, then the method 'Verification' and event 'VerifyPropertyChange' will not work
  2. Try to use methods 'CreateViewModel', 'GetViewModel' or 'GetModel' instead of the constructor
  3. Methods 'CreateViewModel', 'GetViewModel' and 'GetModel' use a method 'CreateObject'
  4. Try to redefine the Method 'Initialize' to the place of use of the constructor
  5. Similar methods in the model work the same as in the view-model.

The performance of the model is tested by tests. The performance of the view-model is tested by tests.

⚠️ **GitHub.com Fallback** ⚠️