2

Iam new to c# windows phone development and Iam attempting to build a simple calculator application using the mvvm design pattern. I have a model class currently with one string variable. this is bound to my calculator screen which is a textbox. I also have a number "1" button. when this is pressed, i want the textbox "screen" to update the value. this is done in a command class that implements ICommand interface. Unfortunately this isnt working currently and I cant figure out where the problem is. below is my model class. its very basic.

namespace PhoneApp2.model
{
public class Sum : INotifyPropertyChanged
{

    private string _enteredVal;


    public string EnteredVal
    {
        get { return _enteredVal ; }
        set
        {
            _enteredVal = value;
            RaisePropertyChanged("EnteredVal");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void RaisePropertyChanged(string propName)
    {
      if (this.PropertyChanged != null)
        {
            this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }
    } 

}

next is my xaml file for the mainpage. currently i have the no. 1 button linked to a command class execute() method. and my screen textbox has a binding to my Enteredvalue string. obviously this doesnt look like the ideal way to do it but iam learning it this way as its how some applications are being developed where iam doing an internship.

<Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.Resources>
            <commands:UpdateScreenCommand x:Key="myCommand"/>
        </Grid.Resources>

            <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            </Grid.RowDefinitions>


           <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
            <TextBlock Text="Calculator" Style="{StaticResource PhoneTextNormalStyle}" Margin="12,0"/>

           </StackPanel>

           <!--ContentPanel - place additional content here-->
           <Grid x:Name="ContentPanel" Grid.Row="1" Margin="0,143,0,0" >
           <Grid.RowDefinitions>
                <RowDefinition Height="1*"/>
                <RowDefinition Height="1*"/>
                <RowDefinition Height="1*"/>
                <RowDefinition Height="1*"/>

            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="1*"/>
                <ColumnDefinition Width="1*"/>
                <ColumnDefinition Width="1*"/>
                <ColumnDefinition Width="1*"/>
            </Grid.ColumnDefinitions>

            <Button Content="1"   Command="{StaticResource myCommand}"   CommandParameter="{Binding}" Height="Auto" Width="Auto" Grid.Row="0" Grid.Column="0"/>
            <Button Content="2"   Height="Auto" Width="Auto" Grid.Row="0" Grid.Column="1"/>
            <Button Content="3"   Height="Auto" Width="Auto" Grid.Row="0" Grid.Column="2"/>
            <Button Content="+"   Height="Auto" Width="Auto" Grid.Row="0" Grid.Column="3"/>
            <Button Content="4"   Height="Auto" Width="Auto" Grid.Row="1" Grid.Column="0"/>
            <Button Content="5"   Height="Auto" Width="Auto" Grid.Row="1" Grid.Column="1"/>
            <Button Content="6"   Height="Auto" Width="Auto" Grid.Row="1" Grid.Column="2"/>
            <Button Content="-"   Height="Auto" Width="Auto" Grid.Row="1" Grid.Column="3"/>
            <Button Content="7"   Height="Auto" Width="Auto" Grid.Row="2" Grid.Column="0"/>
            <Button Content="8"   Height="Auto" Width="Auto" Grid.Row="2" Grid.Column="1"/>
            <Button Content="9"   Height="Auto" Width="Auto" Grid.Row="2" Grid.Column="2"/>
            <Button Content="/"   Height="Auto" Width="Auto" Grid.Row="2" Grid.Column="3"/>
            <Button Content="0"   Height="Auto" Width="Auto" Grid.Row="3" Grid.Column="1"/>
            <Button Content="*"   Height="Auto" Width="Auto" Grid.Row="3" Grid.Column="3"/>
            <Button Content="C"   Height="Auto" Width="Auto" Grid.Row="3" Grid.Column="0"/>
            <Button Content="="   Height="Auto" Width="Auto" Grid.Row="3" Grid.Column="2"/>
           </Grid>
           <Grid  MinHeight="107" Margin="10,10,0,0" Grid.Row="1" VerticalAlignment="Top"     Width="458" RenderTransformOrigin="0.467,-0.089">
            <TextBox Height="Auto"  Text="{Binding EnteredValue, Mode=OneWay}" TextWrapping="Wrap"  VerticalAlignment="Center" Width="Auto" />
           </Grid>


           </Grid>

and finally I have the command class. the execute method appends the _enteredvalue string. which seems to work when debugging. my issue seems to be coming for the raisepropertychanged method being passed a null. but iam not sure how to fix this.

namespace PhoneApp2.commands
{
public class UpdateScreenCommand : ICommand
{
    public bool CanExecute(object parameter)
    {
        var m = (Sum) parameter;
        return true;
    }

    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter)
    {
         var m = (Sum) parameter;
         m.EnteredVal += "1";
    }
 }
}

again i know this is a bit of a bastardisation of mvvm but iam trying to learn how its implemented where i work. any help is greatly appreciated.

filthy_wizard
  • 740
  • 11
  • 25
  • so in what way this isn't working, any exception thrown? if no exception, have you tried to put breakpoint in `Execute` method to make sure it is fired? – har07 Feb 01 '14 at 13:37
  • or if anyone could point me in the direction of a good mvvm tutorial that would be great – filthy_wizard Feb 01 '14 at 13:46
  • no exceptions and _enteredvalue is being set to 1. when i debug this.propertychanged is equal to null so it skips over the if(this.propertchanged!=null)) – filthy_wizard Feb 01 '14 at 14:12
  • so essentially everthing is working up until the RaisePropertyChanged() method is called. – filthy_wizard Feb 01 '14 at 14:19

1 Answers1

0

The thing that bothers me the most from your current implementation of MVVM is the Command. Basically we only need to create one class that implements ICommand. Then we can create multiple properties from that class, each can execute different methods/codes. Example implementation of ICommand from another SO post:

public class ActionCommand : ICommand
{
    private readonly Action _action;

    public ActionCommand(Action action)
    {
        _action = action;
    }

    public void Execute(object parameter)
    {
        _action();
    }

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

    public event EventHandler CanExecuteChanged;
}

Then we usually put command properties mentioned above in the ViewModel:

public class Sum : INotifyPropertyChanged
{   
    private ICommand _addOneCommand;
    public ICommand AddOneCommand
    {
        get 
        {
            return _addOneCommand
                ?? (_addOneCommand = new ActionCommand(() => 
                {
                    EnteredVal += "1";
                }));
        }
    }
    .....
    .....
}

Assuming Page's DataContext has been set properly to Sum, we can bind the button to Command property in Sum as follows:

<Button Content="1" Command="{AddOneCommand}" Height="Auto" Width="Auto" Grid.Row="0" Grid.Column="0"/>

Some tutorials on getting started with MVVM in Windows Phone application:

Community
  • 1
  • 1
har07
  • 88,338
  • 12
  • 84
  • 137
  • also i think having a command for just adding a number to the claculator screen is probably not required as it is all just changing the view. could possibly be using the wrong design pattern here – filthy_wizard Feb 01 '14 at 14:31
  • I think this is the right pattern. It is changing data, and view display the updated data. Changing view only means for example, change width/height of a button, change background color, etc, without changing data. In this case, it will be better to implement ICommand that accept parameter. Hence you can bind all button to single command, each button set to pass different parameter to the command – har07 Feb 01 '14 at 14:43
  • yeah, that paticular implementation of mvvm iam using here is obviously wrong – filthy_wizard Feb 01 '14 at 14:52