I have a form with a textbox bound to an integer, and a button. Now, when the value of the textbox is invalid, I want to immediately disable the button.
Normally, one would put a Can() method in the VM, and trigger a NotifyOfPropertyChange in the property's setter. However, if the user inputs a non numeric value for example, the textbox is invalid, but the property setter is never called, so I can't notify/disable the button.
So, how do I disable the button, when the user inputs an invalid value that doesn't cause the property setter to get called? My knowledge of CM is limited as I've just started out.
I've found the best approach to this problem is to make the property a string instead and do the necessary string to integer conversion in your property setter. If the conversion is invalid, then you could reset the TextBox value to a default value. This way your property setter will always get fired.
If your model has an integer property, then it makes sense to place the string version on the view model, as this is only really related to the UI, rather than business logic.
If you don't wish the user to be able to input non digit characters, then you can use a masked text box, such as the one included in the Extended WPF Toolkit, or in a third party control suite such as those offered by Telerik or Infragistics.
I'd use a MaskedTextBox instead and set the mask to integer only.
Related
Let's say I have a ViewModel with a data type of float and implements INotifyPropertyChanged interface.
private float Amount;
And then in my UI:
<TextBox Text="{x:Bind Amount, Mode=TwoWay}" />
What happens is that when I'm trying to type the character . (period), the text cursor goes back to the start and just appears right after two presses of period. What could be causing this behavior?
I have tested the code when UpdateSourceTrigger=PropertyChanged as mentioned in the comments. The problem is that PropertyChanged causes the binding to update immediately after each keystroke. Because of this the behavior is quite upredicatable when the input does not contain a valid float. I have seen three different behaviors so far. Once only one digit is entered and period right after that, the binding sometimes converts it to a decimal:
But sometimes this did not happen and the control just let me enter 3. without any change. The behavior is seems really random. The key is that the value that is set to the backing property is then reflected in the UI by virtue of PropertyChanged event and data binding, which causes the text to change and cursor to jump.
Simply said, the problem here is the fact that the property is a float while the input accepts any string. The solution to your problem could be to use a string property for the binding, like AmountText and then in the setter verify that the text is actually a valid float, parse it and manually set the Amount property. This way you would preserve the "immediate" updating of the value as soon as a valid input is entered while you would also avoid the weird behavior you are seeing.
Also check out the WinRTXamlToolkit and its NumericUpDown control, which might be a better solution for your goal as it provides a natural way for the user to enter numeric values.
I'm using the Extended WPF ToolKit's DecimalUpDown control (v1.7). The control behaves as I expect when using the spinner controls but not when text is edited directly. This is a basic MVVM WPF app with the control bound to a View Model decimal property named CurrentWidth.
In the ViewModel there are various validation rules being enforced for CurrentWidth, at the end of the property it does a RaisePropertyChange("CurrentWidth"); sometimes leaving CurrentWidth unchanged if the value doesn't validate.
All the error checking, value reverting etc works when change is made with the spinner controls. When the user enters text directly in the box, the validation still works but the box is left showing what the user entered. When I send out some debug info, both the Value property and Text properties have the correct unmodified value but the box still shows the user entered value. I tried adding a LostFocus event handler and called InvalidateVisual() on the sender control and even tried an UpdateLayout() as well but after tabbing off the control, the user entered text still shows. Anyone know how to get it to reflect the actual current value?
Download WPFToolkit 1.8.0. This bug is solved there.
I have a two way binding on a string dependency property to the Text of a TextBox.
The binding looks like this:
Text="{Binding MyValue, Mode=TwoWay}"
I have some code that fires in OnKeyUp (in an attached property) that sets MyValue. But rather than taking my value and applying it to the Text property, it is going the other way around.
Here are the sequence of events:
The user enters a string of text that looks like this: 0299900650
The user presses enter.
In my on key up I set MyValue to 2999 and move to the focus to the next field.
The setter for MyValue fires and does a NotifiyPropertyChanged with 2999
The LostFocus fires.
The setter for MyValue fires and does a NotifiyPropertyChanged with 0299900650.
It seems to me that my value is not making it back to "TextBox.Text" somehow. When I loose focus the TextBox is updating the value of the string with what it has in the Text property (the unchanged value because my change did not get back.)
Is there some WPF magic I am not aware of here?
NOTE: I have double checked my bindings. (Besides they work from the UI so I imagine they are correct going to the UI.)
NOTE II: When I say the "user enters a string", it is really a scanned barcode. But since I am using a keyboard wedge, it is as if it was typed in. (However, the whole point of setting the value is because I am doing something different if the user scans as apposed to typing.)
UPDATE: I found this was due to another property having a side effect. I was able to fix the problem.
You simply jump into the concurency conflict on WPF binding messaging.
To prove that, do the following:
remove your OnKeyUp even handler
and do the same you did. On Enter click binding mechanism fires and sets your code behind property.
In case when you make on KeyUp, you new value 2999 is surpressed by the binding after.
To manage this correctly make use of Converter and get rid of OnKeyDown even subscription.
I found this was due to another property having a side effect. I was able to fix the problem by fixing that side effect.
I am developing a WPF application in which i am using a textbox that is bind to an int field of my POCO entity, when i clear the textbox i want my currentobject to be invalid as this is a non nullable field.
But the thing is when i clear my textbox, it convert to string.empty that can ot be set to an int value, so my int field never gets updated and my object remains Valid.
Kindly suggest some logical solution to this.
One approach is to bind to a string value instead (probably added to a view model if you don't want to pollute your model), and then in the setter for the string property, convert the string to an integer to store on your int property.
As i see it, you should not be able to set an 'empty' value to an int control.
Maybe you could use the IntegerUpDown control in the Extended WPF Toolkit which allows you to provide a watermark to show text in place of a NULL Value or set a default value, which could be 0.
It also has button spinners, which can be hidden if needed.
i copied my answer from here. i hope it helps you too.
if your viewmodel has an Property of type int, then your binding just
works if your view got input which is convertable to int. otherwise
your viewmodel will never be informed. there are 2 ways now:
first: you make sure that your view just can take numeric input (with
your numeric textbox) and the viewmodel property can be int.
or second: your viewmodel property type is typeof string and you use
IDataErrorInfo to let the view know when the input is not numeric.
By default WPF should display the ErrorTemplate when a validation error occurs, and this includes validation errors caused by invalid casts, such as trying to store a string field in an int. The default ErrorTemplate for a TextBox is a red border, and for most users this is an indication that something is incorrect and the changes will not get saved.
If you want something more than that, you could try using an IValueConverter in your binding which attempts to cast the value into a int, and will return 0 (or some invalid value) if it fails so your object will get updated with something no matter what the user enters.
What code should I write to prevent any special characters except '_' (underscore) while entering the name in text box?
If such character exist then a popup message should appear.
Rather than me writing the code for you, here are the basic steps required for accomplishing such a feat:
Handle the KeyDown event for your TextBox control.
Use something like the Char.IsSymbol method to verify whether or not the character that they typed is allowed. Make sure you check explicitly for the underscore, because you want to allow it as a special case of other symbols.
If a valid character is typed, do nothing. WinForms will take care of inserting it into the textbox.
However, if an invalid character is typed, you need to show the user a message, informing them that the character is not accepted by the textbox. A couple of things to do here:
Set the e.SuppressKeyPress property to True. This will prevent the character from appearing in the textbox.
Display a tooltip window on the textbox, indicating that the character the user typed is not accepted by the textbox and informing them what characters are considered valid input.
The easiest way to do this is using the ToolTip class. Add this control to your form at design time, and display it when appropriate using one of the overloads of the Show method.
In particular, you'll want to use one of the overloads that allows you to specify an IWin32Window to associate the tooltip with (this is your textbox control).
Alternatively, instead of a tooltip, you can display a little error icon next to the textbox control, informing the user that their last input was invalid. This is easy to implement using an ErrorProvider control. Add it to your form at design time, just like the tooltip control, and call the SetError method at run-time to display an error message.
Whatever you do, do not display a message box! That disrupts the user trying to type, and it's likely that they'll inadvertently dismiss it by typing the next letter they wanted to type.
Add a handler to the TextBox's KeyDown event. You can examine which key was pressed there, and do whatever you want with it, including popping up a message box.