共用方式為


Reusing ViewModels in a Universal App – Part 3

To restate where part 2 ended – We took the MyCalc app and created an empty ViewModel class.  We then implemented DelegateCommand so we could expose ICommand objects from the ViewModel.  We used that to create commands for the majority of the buttons and modified the XAML to use them.  This allowed us to remove some code from the View.

Binding to EnterText

This next step we want to get rid of the coupling to EnterBox.  Fortunately this is pretty trivial.  The solution is a simple data binding.  There are just 2 details we need to see to while settings up the binding.  The first is to make the binding 2 way, so as the control changes the new value is pushed into the View Model.  The second is to set the update mode so that the binding update occurs on each keystroke.

What we wind up with is this:

            <TextBox

                x:Name="_EnterBox"

                Grid.Column="0"

                Grid.Row="1"

                Margin="4"

                Width="400"

                FontSize="32"

                Text="{Binding EnterText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"

                />

 

Now the View can just interact w/ EnterText rather than the control.  It also doesn’t need that code we added to copy the string back and forth between the control and view model.

Number Mode

To unblock the next set of changes we need to make the view model aware of the number nodes – decimal vs hex.  There are multiple ways we can do this – for example we could have a bool IsHex property.  However I personally prefer an enum.

Not only does the enum make the code more readable, but it also sets us up to support other number modes in the future.

    enumCalculatorViewMode

    {

        Decimal,

        Hex

    }

 

        publicCalculatorViewMode Mode

        {

            get

            {

                return _mode;

            }

            set

            {

                if(_mode != value)

                {

                    _mode = value;

                    _addDigitCommand.RaiseCanExecuteChanged();

                    RaisePropertyChanged("Mode");

                }

            }

        }

 

We also update the View code so that when the radio buttons are changed we update this ViewModel property appropriately.

Supporting Hex Entry

With that property in the view model we now have the information we need to correctly enable/disable the A-F buttons. 

We update the can execute to correctly compute if the hex buttons are enabled.  In addition in the Mode setter we raise the CanExecuteChanged event for the AddDigitCommand.

        privatebool OnAddDigitCanExecute(object parameter)

        {

            var stringParameter = (string)parameter;

 

            switch(stringParameter)

            {

                case"0":

                case"1":

                case"2":

                case"3":

                case"4":

                case"5":

                case"6":

                case"7":

                case"8":

                case"9":

                    returntrue;

                case"A":

                case"B":

                case"C":

                case"D":

                case"E":

                case"F":

                    return (Mode == CalculatorViewMode.Hex);

  default:

                    returnfalse;

            }

        }

 

We can then update the XAML and View code just like we did for the 0-9 buttons.

Enter Button

The last thing we are going to do in this part is convert the Enter button to use the View Model.  Just like the other buttons we add a new command, wire it up in the XAML and remove the obsolete code from the View.

I called it PushCommand, since that is the logical operation of the Enter button and here is its implementation:

        privatevoid OnPushExecuted(object parameter)

        {

            NumberStyles styles;

 

            if (Mode == CalculatorViewMode.Hex)

            {

                styles = NumberStyles.HexNumber;

            }

            else

            {

  styles = NumberStyles.Integer;

            }

 

            Int64 value;

 

            if (Int64.TryParse(EnterText, styles, CultureInfo.CurrentCulture, out value))

            {

                _calc.Push(value);

                EnterText = String.Empty;

            }

        }

 

        privatebool OnPushCanExecute(object parameter)

        {

            return (EnterText.Length > 0);

        }

 

Wrapping it up

This part introduced 2 way bindings as a way to link a TextBox control with a ViewModel property.  By adding the Mode property to the ViewModel we were able to move the remaining Button’s to use ICommand.

This also shows how easy enhancing the view model is once you have some ViewModel infrastructure coded, like DelegateCommand.

Now all that remains in the View is code to handle displaying the stack and responding to the RadioButtons.  Getting rid of that code will be the subject of the next instalment.

MyCalc - part 3.zip