June 09, 2013

Trying to learn MVVM

I realized the code for my expense app was very messy, and although so far it works, I know that's no excuse for having bad code.. so I've been trying to learn about MVVM but it's trickier to learn and implement than it seems.

Undoubtedly, there are good tutorials about MVVM out there but a lot of them seem very complicated.  I don't want to bother with threading when I am learning about MVVM, I have plenty of other things to worry about!  As usual, the best way to learn is to just get your hands dirty and code the thing yourself.

Here is my stupid example of an MVVM app: The Doggy class is my Model which contains a string for Name, and a bool for IsGoodDoggy.  The ViewModel uses the Model to instantiate a Doggy named Toby and IsGoodDoggy is set to true for now, until I hear that he diarrhea'd on the carpet again.  The View displays the Name of the Doggy and IsGoodDoggy, which displays the text in Yellow if the Doggy is being good, and Red if the Doggy is being bad.

This is the code for my Model:
public class Doggy : INotifyPropertyChanged {
  private string _name;
  public string Name {
    get { return _name; }
    set {
      _name = value;
      OnPropertyChanged("Name");
    }
  }

  private bool _isGoodDoggy;

  public bool IsGoodDoggy {
    get { return _isGoodDoggy; }
    set {
      _isGoodDoggy = value;
      OnPropertyChanged("IsGoodDoggy");
    }
  }

  public event PropertyChangedEventHandler PropertyChanged;

  public void OnPropertyChanged(string property) {
    if (PropertyChanged != null) {
      PropertyChanged("this, new PropertyChangedEventArgs(property));
    }
  }
}

This is the code for my ViewModel:
public class MainViewModel : INotifyPropertyChanged {
  private Doggy _goodDoggy;
  public Doggy GoodDoggy {
    get { return _goodDoggy; }
    set {
      _goodDoggy = value;
      OnPropertyChanged("GoodDoggy");
    }
  }

  public MainViewModel() {

    LoadDoggy();
  }

  private void LoadDoggy() {

    GoodDoggy = new Doggy() {
      Name = "Toby";
      IsGoodDoggy = true
    }
  }

  public event PropertyChangedEventHandler PropertyChanged;

  public void OnPropertyChanged(string property) {
    if (PropertyChanged != null) {
      PropertyChanged(this, new PropertyChangedEventArgs(property);
    }
  }
}

Just my ColorConverter class:
public object ColorConverter : IValueConverter {
  public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
    return (bool)value ? new SolidColorBrush(Colors.Yellow) : new SolidColorBrush(Colors.Red);
  }

public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {

  return (((string)value).ToLower() == "true") ? true : false;
  }
}

In App.xaml, I have defined a few resources to be used application wide, (although I only used these resources in my MainPage.xaml) but whatever
<Application.Resources>
  <local:LocalizedString x:Key="LocalizedStrings" />
  <local:MainViewModel  x:Key="MainViewModel" />
  <local:ColorConverter x:Key="ColorConverter" />
</Application.Resources>

And finally, the MainPage.xaml (the code-behind is unnecessary because I didn't add anything to it yay!!)
Not adding the automatically generated code, just what I added:
<StackPanel DataContext="{StaticResource MainViewModel}">
  <StackPanel Orientation="Horizontal">
    <TextBlock Text="Name: " Margin="5,0,0,20" Width="150"/>
    <TextBlock Text="{Binding GoodDoggy.Name}" Margin="5,0,0,20" Width="150"/>
  </StackPanel>

  <StackPanel Orientation="Horizontal">
    <TextBlock Text="Is Good Dog:" Width="150"/>
    <TextBox Foreground="{Binding GoodDoggy.IsGoodDoggy, Converter={StaticResource ColorConverter}}" Text="{Binding GoodDoggy.IsGoodDoggy, Mode=TwoWay}" Width="150"/>
  </StackPanel>
</StackPanel>

So the default of my app would look like this:


But say Toby decided to take a crap in the house, then my app would look like this:

Entering a string into the TextBox first gets changed by my Converter class into a bool value.  So the string value in the TextBox really represents the bool value of IsGoodDoggy.  Whenever IsGoodDoggy is changed, it tells whoever is interested, and it turns out that the TextBox Foreground color is interested and changes its color accordingly.

By the way, this is real life Toby:
rawr