Monday, September 17, 2012

Simple navigation implementation in my first Windows 8 app - Part 2

As in previous post, I described how to implement simple navigation in Baby Learns to Write. Even it worked as expected, but I don't like the implementation when it's not pure MVVM, I still need to add code to code behind file to make the app works. In this post, I will address it.

First, I will update the commands.
    public abstract class MoveCommand : ICommand
    {
        protected readonly MainPageViewModel ViewModel;

        protected MoveCommand(MainPageViewModel viewModel)
        {
            ViewModel = viewModel;
        }

        public bool CanExecute(object parameter)
        {
            return true;
        }

        public abstract void Execute(object parameter);

        public event EventHandler CanExecuteChanged;
    }

    public class MoveNextCommand : MoveCommand
    {
        public MoveNextCommand(MainPageViewModel viewModel) : base(viewModel)
        {
        }

        public override void Execute(object parameter)
        {
            ViewModel.MoveNext();
        }
    }

    public class MovePreviousCommand : MoveCommand
    {
        public MovePreviousCommand(MainPageViewModel viewModel) : base(viewModel)
        {
        }

        public override void Execute(object parameter)
        {
            ViewModel.MovePrevious();
        }
    }
The most important thing is CanExecute() always return true, and I removed RaiseCanExecuteChanged() as I don't need it anymore.

Then I update the view model
public class MainPageViewModel : INotifyPropertyChanged
    {
        private readonly List _numbers;
        private int _currentIndex;

        public int Number
        {
            get { return _numbers[_currentIndex]; }
        }

        public ICommand MovePreviousCommand { get; private set; }
        public ICommand MoveNextCommand { get; private set; }

        public MainPageViewModel()
        {
            _numbers = new List {1, 2, 3};

            _currentIndex = 0;

            MovePreviousCommand = new MovePreviousCommand(this);
            MoveNextCommand = new MoveNextCommand(this);
        }

        public bool CanMovePrevious
        {
            get { return _currentIndex > 0; }
        }

        public bool CanMoveNext
        {
            get { return _currentIndex < _numbers.Count - 1; }
        }

        public void MovePrevious()
        {
            if (CanMovePrevious)
            {
                _currentIndex--;

                PropertyChanged(this, new PropertyChangedEventArgs("Number"));
                PropertyChanged(this, new PropertyChangedEventArgs("CanMovePrevious"));
                PropertyChanged(this, new PropertyChangedEventArgs("CanMoveNext"));
            }
        }

        public void MoveNext()
        {
            if (CanMoveNext)
            {
                _currentIndex++;

                PropertyChanged(this, new PropertyChangedEventArgs("Number"));
                PropertyChanged(this, new PropertyChangedEventArgs("CanMovePrevious"));
                PropertyChanged(this, new PropertyChangedEventArgs("CanMoveNext"));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
In additional raising the PropterChanged event for Number property, I also raise for CanMovePrevious and CanMoveNext property. These properties are used to bind to the XAML as below
    <StackPanel Background="{StaticResource ApplicationPageBackgroundThemeBrush}" HorizontalAlignment="Center" Orientation="Horizontal" VerticalAlignment="Center">
        </StackPanel>
The last thing I need to do is removing all redundant code from code behind file.
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();

            DataContext = new MainPageViewModel();
        }

        /// 
        /// Invoked when this page is about to be displayed in a Frame.
        /// 
        /// Event data that describes how this page was reached.  The Parameter
        /// property is typically used to configure the page.
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
        }
    }
Now the app is written with pure MVVM.

You can grab the source code from here.

No comments:

Post a Comment