mvvm pattern in c#

This is an implementation in C# of the MVVM pattern as described before.

In this implementation I use the MVVM light toolkit, and some patterns I’ve already described: inversion of control and dependecy injection.

First, lets start with the model:

    public class NoteModel : ObservableObject
    {
        private string _note;
        public string Note
        {
            get { return _note; }
            set { Set(ref _note, value); }
        }

        private bool _isFinished;
        public bool IsFinished
        {
            get { return _isFinished; }
            set { Set(ref _isFinished, value); }
        }
    }

As you can see, when assigning to a property, I use a method provided my the MVVM light library: Set(). This method assigns the new value to the property, and fires the IPropertyChanged event, if the new value differs from the old. The IPropertyChanged event allows the view to refresh automatically.

Now, lets look at the view:

<Page DataContext="{Binding MainViewModel, Source={StaticResource Locator}}">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="10" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Grid Grid.Row="0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="Auto" />
            </Grid.ColumnDefinitions>
            <TextBox Text="{Binding NewNote, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
            <Button Command="{Binding AddNoteCommand}" >
                <Button.Content>
                    <SymbolIcon Symbol="Add" />
                </Button.Content>
            </Button>
        </Grid>
        <ListView ItemsSource="{Binding Notes}" />
    </Grid>
</Page>

I’ve removed all styling informations so everything is easier to understand. Take a look at DataContext: MainViewModel is a property of Locator, and this property is bound to the view. Take a look at the TextBox to see what this means: the Text property is filled with another {Binding NewNote...}, and NewNote is a property of the MainViewModel from above.

There are three types of binding in this example:

  • read binding: The ListView binds itself to the Notes property.
  • read & write in the Textbox: The Mode=TwoWay ensures, user input is written into the property automatically by XAML magic.
  • command binding: the Button binds itself to a property called AddNoteCommand, this property implements the ICommand interface. We’ll see about that.

I recommend you to take a look at this in Visual Studio, this helps you to understand all the other magic XAML stuff.

One last thing to check out: the {StaticResource Locator} part in the DataContext, you’ll find the definition the App.xaml:

<viewModels:ViewModelLocator x:Key="Locator" />

which leads to (in the Presentation project, ViewModels folder):

    public class ViewModelLocator : ViewModelLocatorBase
    {
        public ViewModelLocator()
        {
            ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
            SimpleIoc.Default.Register<IPlatformInformations, PlatformInformations>();
        }
    }

and this leads to (in the View project, ViewModels folder)

    public class ViewModelLocatorBase
    {
        public ViewModelLocatorBase()
        {
            ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
            SimpleIoc.Default.Register<IDataService, DataService>();
            SimpleIoc.Default.Register<MainViewModel>();
        }

        public MainViewModel MainViewModel => SimpleIoc.Default.GetInstance<MainViewModel>();
    }

Now there is the MainViewModel property!
The SimpleIoc part is an implementation of the Inversion of Control pattern, and provided by the Mvvm light library.

Now the ViewModel.
The constructor part:

    public class MainViewModel : ViewModelBase
    {
        private readonly IDataService _dataService;

        //inversion of control: SimpleIoc will contruct this object with the registered IDataService implementation
        public MainViewModel(IDataService dataService)
        {
            _dataService = dataService;

            _addNoteCommand = new RelayCommand(AddNote, () => CanAddNote);
            _deleteNoteCommand = new RelayCommand<NoteModel>(DeleteNote);

            if (IsInDesignMode)
            {
                Notes = new ObservableCollection<NoteModel>()
                {
                    new NoteModel()
                    {
                        Note = "Hello World",
                        IsFinished = false
                    }
                };
            }
            else
            {
                Initialize();
            }
        }

        private async void Initialize()
        {
            Notes = await _dataService.GetTasks();
        }

        private ObservableCollection<NoteModel> _notes;
        public ObservableCollection<NoteModel> Notes
        {
            get { return _notes; }
            set { Set(ref _notes, value); }
        }
    }

MainViewModel inherits from the ViewModelBase, a class provided by the MVVM light library. It has some nice tools integrated, for example the IsInDesignMode propery.

The ObservableCollection takes care of the necessary events firing, so the view can refresh itself if necessary.

The NewNote property is the one filled by the Textbox. Depending on the input, one can create a new note. So every time the value changes (Set returns true if the value has changed), the should reevaluate if a new note could be created.


        private string _newNote;
        public string NewNote
        {
            get { return _newNote; }
            set
            {
                if (Set(ref _newNote, value))
                    _addNoteCommand.RaiseCanExecuteChanged();
            }
        }

The commands:

        private readonly RelayCommand _addNoteCommand;
        public ICommand AddNoteCommand => _addNoteCommand;

        private bool CanAddNote => !string.IsNullOrEmpty(NewNote);

        private void AddNote()
        {
            Notes.Add(new NoteModel() { Note = NewNote });
            NewNote = "";
        }

        private readonly RelayCommand<NoteModel> _deleteNoteCommand;
        public ICommand DeleteNoteCommand => _deleteNoteCommand;

        private void DeleteNote(NoteModel model)
        {
            Notes.Remove(model);
        }

You can pass an object directly to the command, as done with the DeleteNoteCommand, with the CommandParameter property in the view.

Now start the application and play with it a little bit.
You’ll notice two things:

  • Without any code in view, the displayed items are always up to date. Even some basic animations already work
  • The logic is completely divided from the display, you may use the exact same ViewModel in an Android or iOS application

One Comment

Leave a Reply

Your email address will not be published. Required fields are marked *