|
OK - and I though this one was going to be easy!
I want a text box in a WPF form into which the user can enter a currency amount (e.g. $12.34)
I want to be able to give them an error message if they type in rubbish (e.g. "freds cash")
I want to be able to validate for ranges (so they can't for example, enter -ve numbers )
My 1st thought was to bind a standard textbox to my data property, which is a Decimal?, which doesn't work very well, as if the user types rubbish, an exception is thrown which (as far as I can ascertain) I can't catch!) I know I can display an error message/highlight the control if this happens, but this means that what is shown on the screen doesn't match what is in the property that I'm binding to - so what happens if the user now clicks the SAVE button? it saves the 'old' value, not what's on the screen, that's what!
Solutions I have seen include only binding to strings, and then validating the user input in the setter of those strings. Josh Smith does this here[^] While I like this idea, I feel a little uncomfortable - I'd really like to bind to the 'real' data and not a string representation of it.
Other solutions I came across included karl's solution here[^] which looks very interesting.
But I figure, WPF has been around for a while, so surely there's some accepted way of entering monetary amounts?
Am I missing something really obvious, so obvious that nobody's blogging about it? Or, am I just crap at Googling? Or, do I need to look at Josh or Karl's solution and use one of them? Or, is there a better way?
|
|
|
|
|
You need an attached behavior for this. I wrote one for Goldlight that effectively looks like this:
namespace Goldlight.Behaviors
{
using System.Windows;
using System.Windows.Interactivity;
using System.Windows.Input;
using System.Windows.Controls;
using System.Text.RegularExpressions;
public class NumericTextBoxBehavior : Behavior<TextBox>
{
#region Overrides
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.PreviewTextInput += AssociatedObject_PreviewTextInput;
DataObject.AddPastingHandler(AssociatedObject, OnClipboardPaste);
}
protected override void OnDetaching()
{
AssociatedObject.PreviewTextInput -= AssociatedObject_PreviewTextInput;
DataObject.RemovePastingHandler(AssociatedObject, OnClipboardPaste);
}
#endregion
#region Private Methods
private void AssociatedObject_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
var tb = AssociatedObject;
e.Handled = !Validate(e.Text);
}
private void OnClipboardPaste(object sender, DataObjectPastingEventArgs e)
{
var tb = sender as TextBox;
string text = e.SourceDataObject.GetData(e.FormatToApply) as string;
if (!string.IsNullOrEmpty(text) && !Validate(text))
{
e.CancelCommand();
}
}
private bool Validate(string newContent)
{
TextBox tb = AssociatedObject;
string testString = string.Empty;
string pre = string.Empty;
string post = string.Empty;
if (!string.IsNullOrEmpty(tb.SelectedText))
{
pre = tb.Text.Substring(0, tb.SelectionStart);
post = tb.Text.Substring(tb.SelectionStart + tb.SelectionLength,
tb.Text.Length - (tb.SelectionStart + tb.SelectionLength));
}
else
{
pre = tb.Text.Substring(0, tb.CaretIndex);
post = tb.Text.Substring(tb.CaretIndex, tb.Text.Length - tb.CaretIndex);
}
testString = pre + newContent + post;
Regex regExpr = new Regex(@"^([-+]?)(\d*)([,.]?)(\d*)$");
return (regExpr.IsMatch(testString));
}
#endregion
}
} The full Goldlight version does quite a bit more with the regex, but this basic logic holds. Now, all you need to do is attach this to your TextBox .
|
|
|
|
|
Right, the way I've implemented this in Goldlight is shown in this blog entry[^].
I'm not a stalker, I just know things. Oh by the way, you're out of milk. Forgive your enemies - it messes with their heads
My blog | My articles | MoXAML PowerToys | Onyx
modified on Wednesday, March 30, 2011 3:40 PM
|
|
|
|
|
I don't quite know how to reply without sounding as if I have a man-crush on you.
Just looking at the string.Format pattern made my eyes look like those of the snake in The Jungle Book movie!
Thanks!
|
|
|
|
|
No problem. Glad I can help.
|
|
|
|