June 19, 2013

expense tracker - part 6

Made more progress with my AddExpenses UserControl - made a ViewModel class called AddExpenseViewModel that implements all of the logic whenever a user clicks the Add button.  I was able to figure out how to bind my add button functionality in the ViewModel, so my code behind for AddExpenses is clean for now.  Also, I just made the list of expenses a separate ViewModel class, but it is contained in my ExpenseViewModel class.

So here is my new class, my ExpensesCollection class:
public static class ExpensesCollection {
  public static ObservableCollection<Expenses> AllExpenses = new ObservableCollection<Expenses>();
  static IsolatedStorageSettings storage = IsolatedStorageSettings.ApplicationSettings;

  public static bool ContainsExpense(string s) {
    foreach (Expenses e in AllExpenses) {
      if (e.Expense == s) { return true; }
    }
    return false;
  }

  public static Expenses Remove(string s) {
    foreach (Expenses e in AllExpenses) {
      if (e.Expense == s) {
        AllExpenses.Remove(e);
        storage.Remove(s);
        storage.Save();
        return e;
      }
    }
    string message = String.Format("{0} is not in your list", s);
    MessageBox.Show(message);
    return null;
  }

  public static void Add(string s, double d) {
    AllExpenses.Add(new Expenses() { Expense = s, Cost = d });
    if (!storage.Contains(s)) {
      storage.Add(s, d);
    } else {
      storage[s] = d;
    }
    storage.Save();
  }
}
I think there's some room for improvement here but I'll let it be for now.

As a result of this new class I made some changes to my ExpenseViewModel -
Replaced my AllExpenses with ExpensesCollection.AllExpenses, named ExpenseList in my file,
and my new GetSavedExpenses:
private void GetSavedExpenses() {
  foreach (string s in storage.Keys) {
    double d;
    if (Double.TryParse(storage[s].ToString(), out d)) {
      var expense = new Expenses() { Expense = s, Cost = d; };
      ExpenseList.Add(expenses);
    }
  }
}
Yes I realize the if statement is probably unnecessary - the expense, cost pair wouldn't be allowed to be added in the first place if it was an invalid double.  But I have to call TryParse anyway so might as well add a tiny check.

The only changes I made to my AddExpenses.xaml file is binding the text property of my textboxes to properties in my ViewModel -
for txtInput:
Text="{Binding CurrentTxt, Mode=TwoWay}"
and for numInput:
Text="{Binding CurrentNum, Mode=TwoWay}"
And binding my button Command to my AddCommand property in the ViewModel:
Command="{Binding AddCommand}"

Here's the code for the ViewModel itself:
public class AddExpenseViewModel : INotifyPropertyChanged {
  IsolatedStorageSettings storage = IsolatedStorageSettings.ApplicationSettings;

  public AddExpenseViewModel() {
    InitializeCommand();
  }

  #region AddCommand

  private ICommand _AddCommand;
  public ICommand AddCommand {
    get { return _AddCommand; }
    set {
      _AddCommand = value;
      OnPropertyChanged("AddCommand");
    }
  }

  private void InitializeCommand() {
    AddCommand = new AddCommand(UpdateExpensePair);
  }

  private void UpdateExpensePair() {
    var ExpenseStorage = ExpenseViewModel.AllExpenses;

    string s = CurrentTxt;
    double d;
    if (double.TryParse(CurrentNum, out d)) {
      if (ExpensesCollection.ContainsExpense(CurrentTxt) {
        Expenses e = ExpensesCollection.Remove(s);
        d += e.Cost;
      }
      ExpensesCollection.Add(s, d);
    } else {
      MessageBox.Show("Integers and decimals only, please");
    }
  }

  #endregion

  #region Text(Expense) Setting

  const string DEFAULT_TXT = "expense";

  private string _CurrentTxt = "";
  public string CurrentTxt {
    get { return _CurrentTxt; }
    set {
      _CurrentTxt = value;
      OnPropertyChanged("CurrentTxt");
    }
  }

  private bool _DefaultTxtSettings = true;
  public bool DefaultTxtSettings {
    get { return _DefaultTxtSettings; }
    set {
      _DefaultTxtSettings = value;
      OnPropertyChanged("DefaultTxtSettings");
    }
  }

  #endregion

  #region Number(Cost) Settings

  const double DEFAULT_NUM = 0;

  private string _CurrentNum = "";
  public string CurrentNum {
    get { return _CurrentNum; }
    set {
      _CurrentNum = value;
      OnPropertyChanged("CurrentNum");
    }
  }

  private bool _DefaultNumSettings = true;
  public bool DefaultNumSettings {
    get { return _DefaultNumSettings; }
    set {
      _DefaultNumSettings = true;
      OnPropertyChanged("DefaultNumSettings");
    }
  }

  #endregion

  #region INotify Implementation

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

  public event PropertyChangedEventHandler PropertyChanged;

  #endregion
}

#region AddCommand Class

public class AddCommand : ICommand {
  Action _executeMethod;

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

  public event EventHandler CanExecuteChanged;

  public void Execute(object parameter) {
    _executeMethod.Invoke();
  }

  public AddCommand(Action updateExpensePair) {
    _executeMethod = updateExpensePair;
  }
}

#endregion

Whew.  It's still not complete, I have some more work to do with the AddCommand class, like actually putting in logic for CanExecute.  I noticed there are two functions that do similar things - the Add command in my ExpensesCollection class and my UpdateExpensePair() that is called with the Add button is clicked.  In ExpensesCollection, the Add method assumes that the double value is already the correct value - what I mean is that if you add to an expense that already exists, you leave the string alone but update the double value.  That logic is done in UpdateExpensePair(), but I  suppose I could have moved the logic to my Add class.  My question is, where is it better to implement that logic?  Already there are assumptions in my code about the values it is being passed, what if something weird happens and those assumptions end up being wrong?  But I don't want to do unnecessary checking, either.  In school we just cleaned the input in the calling function, and the callee assumes it is being given valid input so that's just what I did here.  Is that convention?  It's probably better to comment the code, warning that this particular function assumes things about its input.  I could probably implement some error handling too, I guess.

Anyway..

Finally, in the MainPage codebehind, I had to instantiate a new AddExpenseViewModel and set AddExpenseViewOnPage.DataContext to that ViewModel.

So I think the basic logic is complete.  Codewise, it's better than my previous version of this app but it doesn't work as seamlessly when the user is interacting with the app itself.  I might have to add codebehind in my AddExpenses UserControl to control the visual appearance of my TextBoxes, but for now I'm ok with that.

I'd also like to add that while I completely revamped the logic - the functionality and appearance still stayed the same and I only had one bug while making these changes, and it was pretty easy to fix.  I was surprised at how seamless these changes were - I guess that's the point of going through all this trouble to implement this pattern!

June 16, 2013

expense tracker - part 5

I've been busy with stuff, but I was able to devote some time this weekend to getting my butt kicked by MVVM.  I know that it's supposed to make things easier, but how can something that is supposed to simplify things be so hard to understand?  I get the concepts - separate your data from your logic from your views, but quite honestly that's easier said than done.

I separated my data into Model, ViewModel, and View folders, as shown:

And I expect to be adding more items, as I've only implemented the very basics of my app (again). Just trying to get things working and responsive, for now.

The Model contains my Expenses class with the following code:
public class Expenses : INotifyPropertyChanged {
  public string Expense { get; set; }
  private double _cost;
  public double Cost {
    get { return _cost; }
    set {
      _cost += value;
      OnPropertyChanged("Cost");
    }
  }

  public event PropertyChangedEventHandler PropertyChanged;

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

So basically what my Model is - it's each key, value pair that will eventually be displayed.  Like, <"Shoes", 50>.  In my previous implementation the Cost was represented by an int, but why not let people put in a decimal value.  When parsing the values, any values with a decimal value would be ignored and I realized that probably isn't a good thing.

I only have one ViewModel so far, my ExpenseViewModel but I'll probably add more as I continue developing this app.  Here's the code:
public class ExpenseViewModel {
  IsolatedStorageSettings storage = IsolatedStorageSettings.ApplicationSettings;
  public static ObservableCollection<Expenses> AllExpenses = new ObservableCollection<Expenses>();

  public ExpenseViewModel() { GetExpenses(); }

  public void GetExpenses() {
    if (storage.Count > 0) { GetSavedExpenses(); }
    else { GetDefaultExpenses(); }
  }

  private void GetDefaultExpenses() {
    AllExpenses.Add(new Expenses() { Expense = "Running Tally", Cost = 0 }));
    storage.Add("Running Tally", 0);

    AllExpenses.Add(new Expenses() { Expense = "Other", Cost = 0 }));
    storage.Add("Other", 0);

    storage.Save();
  }

  private void GetSavedExpenses() {
    foreach (string s in storage.Keys) {
      double d;
      if (Double.TryParse(storage[s].ToString(), out d)) {
        var expense = new Expenses() { Expense = s, Cost = d };
        AllExpenses.Add(expense);
      }
    }
  }

  public void Add(string s, double f) {
    AllExpenses.Add(new Expenses() { Expense = s, Cost = f});
    if (!storage.Contains(s)) {
      storage.Add(s, f);
      storage.Save();
    }
  }
}

I wish there was a better way of displaying the data than loading it every single time the app starts, but that's what I have so far.  I took some ideas from Microsoft's Implementing the Model-View-ViewModel tutorial.  Instead of implementing the INotifyPropertyChanged interface I used the ObservableCollection, which notifies whoever is interested that new items have been added or removed from the current list of data.

Now on to the views.  Here's my ExpenseView.xaml file (with nothing added in the code-behind, yay!)
<UserControl.Resources>
  <DataTemplate x:Key="MyPrettyTemplate">
      <StackPanel Orientation="Horizontal"
                         Background="{StaticResource PhoneAccentBrush}" Margin="5">
        <TextBlock Text="{Binding Expense}:
                          Style="{StaticResource PhoneTextSubtleStyle}"
                          Margin="10" Width="300" />
        <TextBlock Text="$ "
                          Style="{StaticResource PhoneTextSubtleStyle"}
                          Margin="10,10,0,10" />
        <TextBlock Text="{Binding Cost}"
                          Style="{StaticResource PhoneTextSubtleStyle}"
                          Margin="0,10,10,10" />
      </StackPanel>
  </DataTemplate>
</UserControl.Resources>

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
  <LisBox x:Name="ExpenseViewOnPage"
               ItemsSource="{Binding}"
               ItemTemplate="{StaticResource MyPrettyTemplate}" />
</Grid>
MyPrettyTemplate just specifies how the items are to be presented, in ExpenseViewOnPage I give the TextBlock fields a DataContext to go on, and a DataTemplate so they can be pretty.  The DataContext is my ExpenseViewModel's AllExpenses - remember the ObservableCollection<Expenses>?

Here's how it looks.  For some reason I couldn't get the LongListSelector to work with a UserControl, so I used a ListBox but now the TextBlocks don't stretch out like they used to, so I'll have to play around with that:


Here's the code for my AddExpenses.xaml:
<Grid x:Name="LayoutRoot">
  <StackPanel x:Name="AddExpenseViewOnPage">
    <TextBox x:Name="txtInput" Width="438"
                   InputScope="Text" />
    <TextBox x:Name="numInput" Width="438"
                   InputScope="Digits" Margin="0,-10,0,0" />
    <Button x:Name="addBtn" Content="Add" Width="438"
                 Background="{StaticResource PhoneChromeBrush}"
                 Margin="0,-10,0,0" Click="addBtn_Click" />
  </StackPanel>
</Grid>

I didn't do any of the fancy tricks I was so proud of before - greying out default values in the fields and stuff.  I just want to get this working first.

Unfortunately I had to add stuff in my code-behind.  I know that to deal with commands such as Save commands or Add commands and the like, you're supposed to do that in the ViewModel with a RelayCommand but I'll add that later.  So for right now I have a Click handler for my button, but I plan on making a ViewModel for my AddExpenses view and implementing the Command in there.

So here it is:
public partial class AddExpenses : UserControl {
  IsolatedStorageSettings storage = IsolatedStorageSettings.ApplicationSettings;
  public AddExpenses() {
    InitializeComponent();
  }

  private void addBtn_Click(object sender, RoutedEventArgs e) {
    var ExpenseStorage = ExpenseViewModel.AllExpenses;

    string s = txtInput.Text;
    double d;
    if (double.TryParse(numInput.Text, out d)) {
      ExpenseStorage.Add(new Expenses() { Expense = s, Cost = d });
      if (!storage.Contains(s)) {
        storage.Add(s, d);
        storage.Save();
      }
    }
  }
}

Now, for the MainPage.xaml - I'd like to point out here that, in my previous app, I had made two pages for the two main components of my app - the add page and the display page.  Here, I only have one page, but two UserControls for the add and the display functionality.  Now it's starting to remind me a lot of the Pivot template so I'll probably just use that later.
Here's where I import the views:
xmlns:views="clr-namespace:expense_thing_test.View"

And where I bring in the views:
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="'12,0,12,0">
  <StackPanel>
    <views:AddExpenses x:Name="AddExpenseViewOnPage" Visibility="Visible"/>
    <views:ExpenseView x:Name="ExpenseViewOnPage" Visibility="Collapsed"/>
  </StackPanel>
</Grid>

I have code for an app bar but it's all non-functional except for my toggle button, so I won't include it.  Also, I can't explain all the technical details, but basically the app bar is a special control that you can't bind a Command to, so you can't implement pure MVVM with it.  There are ways around this but as I don't even understand RelayCommand yet I'm not going to mess with that yet.

Here is my code-behind in my Mainpage class:
public partial class Mainpage : PhoneApplicationpage {
  private ExpenseViewModel vm;
  public Mainpage() {
    InitializeComponent();
 
    vm = new ExpenseViewModel();
    ExpenseViewOnPage.DataContext = ExpenseViewModel.AllExpenses;
  }

  private void display_button_Click(object sender, EventArgs e) {
    if (AddExpenseViewOnPage.Visibility == Visibility.Visible) {
      AddExpenseViewOnPage.Visibility = Visibility.Collapsed;
      ExpenseViewOnPage.Visibility = Visibility.Visible;
    } else {
      ExpenseViewOnPage.Visibility = Visibility.Collapsed;
      AddExpenseViewOnPage.Visibility = Visibility.Visible;
    }
  }
}

June 13, 2013

CSS is actually kind of cool

I've been revamping my blog over the past two days. I actually wouldn't call it revamping.. that implies that I did a full-on makeover and added lots of spiffy stuff. No, I've just been tweaking on what I've had so far, and now I feel that it's easier to navigate and looks cleaner.  I never bothered to learn CSS until I was forced to dabble in it at work, and I can say that it's helped majorly. The last time I tried a full-on revamping on blogger I got lost in all the CSS but now I get to use it to my advantage. What I never realized before is that it enables a separation of presentation and content, just like what I'm trying to do in my app. An example is how I made any code I post on here a CSS class, so instead of manually formatting it every time I just go in the HTML and set it to a div class. That approach bears an odd resemblence to DataTemplates in WPF.

It's just like my dad told me when I took my first few CSE classes - "The more you know, well, the more you know". That is so true in computer science. And a bit discouraging to novice programmers - the amount of information that you know you don't know is just overwhelming.  But I've found that basic principles are common to all flavors  of coding.  I had previously dismissed HTML and CSS as mindless tools used to quickly patch up a website, unaware that the two used together are characteristic of the functionality and simplicity of a powerful and well-known programming paradigm.

June 10, 2013

Stupid code

Has anyone ever seen code that literally makes you laugh?

I was doing some practice problems earlier today, one of them was implementing addition using only bit operators.  After that I implemented addition that only uses increment/decrement operators, just for fun:


int dumb_addition(int a, int b) {

  int temp_a = a, temp_b = b, sum = 0;
  while (temp_a > 0) {
    sum++;
    temp_a--;
  }
  while (temp_b > 0) {
    sum++;
    temp_b--;
  }
  return sum;
}

Nevermind the useless temp variables or the fact that this won't work for negative numbers.


Here's some code I ran comparing dumb_addition with my bit_addition function, just to illustrate how terrible my dumb_addition function was:


static void Main() {

  string s = "Elapsed ticks for {0} is: {1}";
  var stopwatch = new Stopwatch();
  stopwatch.Start();
  int x = bit_addition(int.MaxValue, int.MaxValue);
  stopwatch.Stop();
  Console.WriteLine(String.Format(s, "bit_addition", stopwatch.ElapsedTicks));

  stopwatch.Reset();

  stopwatch.Start();
  x = dumb_addition(int.MaxValue, int.MaxValue);
  stopwatch.Stop();
  Console.WriteLine(String.Format(s, "dumb_addition", stopwatch.ElapsedTicks));
}

With the output:

Elapsed ticks for bit_addition is: 769
Elapsed ticks for dumb_addition is: 31337684

Brute force isn't always the answer, kids :(


Speaking of code that makes you laugh, I remember seeing some kid's program where he commented EVERY single line of code.  Most amusing was the fact that he commented the statement "return x" with "//return x".  I had a chuckle over that one after shaking my head disapprovingly.

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

June 06, 2013

expense tracker - part 4

Here's my app now.  Looks better


But for now the code still looks messy.  Now that I've got the basic functionality I want and I'm starting to learn more about MVVM, I think I'm gonna start moving my code around so it follows those principles.  I've been experimenting with data binding and the IConverter interface as well - I'm binding both Textbox Foreground colors to a Boolean value and using a Converter class, so now I don't have to manually update the color in my code because it automatically fires depending whether the Boolean satisifies the default settings or not.

Here's a neat little MessageBox trick I discovered:

Timing it so the purple shows was quite tricky

Now when the user clicks delete, the app verifies the action before removing all the data.  I'm sure there would have been instances where I accidentally brush the trash can and inadvertently remove all of my data.  At least now this is slightly more idiot proof.  Here's the code used to implement that:

private void clear_button_Click(object sender, EventArgs e) {
  MessageBoxButton button = MessageBoxButton.OKCancel;
  string s = "";
  MessageBoxResult result = MessageBox.Show("Are you sure you want to clear all values?", s, button);
  if (result == MessageBoxResult.OK)
     my_storage.Clear();
}

The pencil button on the app bar is the edit button, which I haven't implemented yet.  When you click it all it does is display a MessageBox informing you that you clicked it.  It's not very helpful yet but I'll make it so the user can remove single fields that they no longer need.  And I'll probably keep the app bar at four buttons, any more and it'll start to look too busy.

Another nifty feature - the "running tally" text at the bottom of the main page, and the LongListSelector used to display all of the name, value pairs are data bound to the user's current accent color, so it's not my fault it the user doesn't like the color.  I'm just starting to get used to this data binding stuff but I've found I can simplify the code and add many more cool features with it.

June 02, 2013

Big lessons for a tiny app.

This very simple app has really taught me the values of source code repositories, good design patterns, reusable code, regression testing, modularity, and good user interface design, because I think I violated all of them.  Dang.