So right now the user is allowed to remove single fields from clicking on a name in the display list, but they can't edit it. I could direct the user to a separate edit page but that seems clunky. I like the consistency and look of the MessageBox, but it looks like I'll have to implement my own to get the functionality I want.
And actually, deleting a single field was difficult enough. I couldn't get the Binding Command to work on a single field in my ItemsControl so I had to go with Click event handlers in the code-behind. Unlike Binding Commands, I can't pass on a parameter so that was tricky - I had to do some shenanigans to get it to work.
Anyway, say you want to remove a field from your list - you just click it and a MessageBox pops up, allowing you to remove it or cancel. A second MessageBox pops up confirming that you did, in fact, remove it. That might get annoying if you use it a lot so I'm thinking about taking it out.
And now no more lunch. Although it bothers me that Other still shows up even when it's 0, I'm going to change that. Also, if you look carefully, you can see that the "Lunch" button and its text is brighter than the rest of the fields, due to it being focused. I didn't implement that, it comes with the Button, but I like how it looks.
I had to play around with Focus stuff in order to get it to work, as Click events can't pass parameters and I couldn't bind to a specific item that is contained in an ItemsControl. Ideally I would use a Binding Command, where you can pass on a parameter, but I was having a lot of trouble implementing that. Anyhow, here is the click event in my code:
private void List_Button_Click(object sender, RoutedEventArgs e) {
string name = "";
decimal cost = 0;
GetFocusedNameCost(out name, out cost);
vm.MouseClick(name, cost); // where vm is an instance of my ViewModel
}
private static void GetFocusedNameCost(out string name, out decimal cost) {
var focusedElement = FocusManager.GetFocusedElement();
StackPanel s = (StackPanel)(((Button)focusedElement).Content);
name = ((TextBlock)(s.Children[0])).Text;
Decimal.TryParse(((TextBlock)s.Children[2]).Text, out cost);
}
string name = "";
decimal cost = 0;
GetFocusedNameCost(out name, out cost);
vm.MouseClick(name, cost); // where vm is an instance of my ViewModel
}
private static void GetFocusedNameCost(out string name, out decimal cost) {
var focusedElement = FocusManager.GetFocusedElement();
StackPanel s = (StackPanel)(((Button)focusedElement).Content);
name = ((TextBlock)(s.Children[0])).Text;
Decimal.TryParse(((TextBlock)s.Children[2]).Text, out cost);
}
And in my ViewModel for this page:
public void MouseClick(string name, decimal cost) {
string title = String.Format("{0}: ${1}", name, cost.ToString());
var result = Guide.BeginShowMessageBox(title, " ", new string[] { "remove", "cancel" }, 0, MessageBoxIcon.None, null, null);
int? user_choice = Guide.EndShowMessageBox(result);
if (user_choise == 0) {
theyclickedremove(name, cost);
}
}
string title = String.Format("{0}: ${1}", name, cost.ToString());
var result = Guide.BeginShowMessageBox(title, " ", new string[] { "remove", "cancel" }, 0, MessageBoxIcon.None, null, null);
int? user_choice = Guide.EndShowMessageBox(result);
if (user_choise == 0) {
theyclickedremove(name, cost);
}
}
Where theyclickedremove(name, cost) just goes and removes the appropriate items from storage and the display list. Right now the variable names are confusing and I need to do some minor refactoring so I'll just leave it out for now.
So now my app is mainly functional, if not totally intuitive. Right now, if the user wants to subtract, say, $5 from a field, they'll have to remove it from the list and re-enter the field with the new value. At least it's better than clearing the entire list, but I want to make that process easier. Also I want to implement an option that clears the list at the beginning of every month. Shouldn't be too hard.