Green (Screen) Computing
- by onefloridacoder
I recently was given an assignment to create a UX where a user could use the up and down arrow keys, as well as the tab and enter keys to move through a Silverlight datagrid that is going be used as part of a high throughput data entry UI. And to be honest, I’ve not trapped key codes since I coded JavaScript a few years ago. Although the frameworks I’m using made it easy, it wasn’t without some trial and error. The other thing that bothered me was that the customer tossed this into the use case as they were delivering the use case. Fine. I’ll take a whack at anything and beat up myself and beg (I’m not beyond begging for help) the community for help to get something done if I have to. It wasn’t as bad as I thought and I thought I would hopefully save someone a few keystrokes if you wanted to build a green screen for your customer. Here’s the ValueConverter to handle changing the strings to decimals and then back again. The value is a nullable valuetype so there are few extra steps to take. Usually the “ConvertBack()” method doesn’t get addressed but in this case we have two-way binding and the converter needs to ensure that if the user doesn’t enter a value it will remain null when the value is reapplied to the model object’s setter. 1: using System;
2: using System.Windows.Data;
3: using System.Globalization;
4:
5: public class NullableDecimalToStringConverter : IValueConverter
6: {
7: public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
8: {
9: if (!(((decimal?)value).HasValue))
10: {
11: return (decimal?)null;
12: }
13: if (!(value is decimal))
14: {
15: throw new ArgumentException("The value must be of type decimal");
16: }
17:
18: NumberFormatInfo nfi = culture.NumberFormat;
19: nfi.NumberDecimalDigits = 4;
20:
21: return ((decimal)value).ToString("N", nfi);
22: }
23:
24: public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
25: {
26: decimal nullableDecimal;
27: decimal.TryParse(value.ToString(), out nullableDecimal);
28:
29: return nullableDecimal == 0 ? null : nullableDecimal.ToString();
30: }
31: }
The ConvertBack() method uses TryParse to create a value from the incoming string so if the parse fails, we get a null value back, which is what we would expect. But while I was testing I realized that if the user types something like “2..4” instead of “2.4”, TryParse will fail and still return a null. The user is getting “puuu-lenty” of eye-candy to ensure they know how many values are affected in this particular view.
Here’s the XAML code. This is the simple part, we just have a DataGrid with one column here that’s bound to the the appropriate ViewModel property with the Converter referenced as well.
1: <data:DataGridTextColumn
2: Header="On-Hand"
3: Binding="{Binding Quantity,
4: Mode=TwoWay,
5: Converter={StaticResource DecimalToStringConverter}}"
6: IsReadOnly="False" />
Nothing too magical here. Just some XAML to hook things up.
Here’s the code behind that’s handling the DataGridKeyup event. These are wired to a local/private method but could be converted to something the ViewModel could use, but I just need to get this working for now.
1: // Wire up happens in the constructor
2: this.PicDataGrid.KeyUp += (s, e) => this.HandleKeyUp(e);
1: // DataGrid.BeginEdit fires when DataGrid.KeyUp fires.
2: private void HandleKeyUp(KeyEventArgs args)
3: {
4: if (args.Key == Key.Down ||
5: args.Key == Key.Up ||
6: args.Key == Key.Tab ||
7: args.Key == Key.Enter )
8: {
9: this.PicDataGrid.BeginEdit();
10: }
11: }
And that’s it. The ValueConverter was the biggest problem starting out because I was using an existing converter that didn’t take nullable value types into account. Once the converter was passing back the appropriate value (null, “#.####”) the grid cell(s) and the model objects started working as I needed them to.
HTH.