I bound my WPF form to a class's property that is Decimal. The textbox automatically higlighted in red if the user enter invalid format (string instead of decimal). However, I want to make it more secure by validating before storing the inserted data into database.
The problem is, whenever a user enter a non decimal value, the binding will return 0 instead of null or error. So it managed to get into the database without second level validation.
What is the best way to validate a WPF binding to a decimal? Right now it wont return null so I do not have any means to capture the error.
Here is how I bound the textbox
<TextBox x:Name="stockTxtBx" Grid.Row="3" Grid.Column="1" Style="{StaticResource StandardBox}" Text="{Binding StockOnHand}"/>
Also, where can I modify to add a validation?
The problem is, whenever a user enter a non decimal value, the binding will return 0 instead of null or error
You are slightly incorrect in your above statement. What actually happens when a user enters some text that has an invalid type for a particular field is this:
The invalid text causes a red border (or other decoration depending on the ErrorTemplate value) to appear around the TextBox
The data bound property value remains at the last valid value that was entered
So, in your case, that last valid value may have been 0, which is why you assumed that an invalid value would always return 0. So in fact, only the invalid value is ignored, while the last valid value remains.
However, to improve this issue, you have several options. One way would be to check the value of the Validation.HasError Attached Property before you save the data. Obviously, if you detect that any errors are present, then you would popup a message to alert the user, rather than continuing to save. You can find out more about this method from the Binding Validation.HasError property in MVVM question.
Another option would be to restrict the textual input of a particular TextBox so that it would not be possible to enter non numeric keys. I won't go over the details on how to do this again here, instead preferring to request that you look at the answers to the Numeric Data Entry in WPF question, here on Stack Overflow.
Related
I have a Textedit Control that I want to behave in a certain way:
When the Control has input focus, I want to only allow the input of positive whole Numbers (not zero). I achieve that by using Properties.Mask, which works fine.
When the Control does NOT have input focus, I want it to Display the entered number but with ",00" at the end.
So basically, while I enter something, I only see what I enter e.g. "17" but when the Control loses focus, I want it to show "17,00". So that I am only allowed to enter whole positive numbers but the Control will always add ",00" afterwards.
My understanding is that there are basically two different "modes": DisplayMode and EditMode.
EditMode = The Control has focus.
DisplayMode = The Control does not have focus.
In EditMode, I can type things into my Textedit Control. What I can and can not enter is determined by the Mask.
When I lose focus, it goes into DisplayMode. Here I cant type anything into the TextEdit but now the displayed text is not determined by the mask any more but by the Property "Properties.DisplayFormat". So to achieve my goal, I tried to set the DisplayFormat.FormatString to "0.00", so that it would always show two decimal places "x,00".
Somehow, this doesn't work as expected. The DisplayFormat doesn't seem to do anything and even in DisplayMode, the TextEdit still shows just the whole number without the decimal places.
I realize that I could use events to work around this problem but I think that's what DisplayFormat, EditFormat and Mask are for and I really don't want to handle multiple events for something that small.
Accodring to DevExpress Knowledge Base topic DisplayFormat is not working in unbound mode.
Problems with formatting occurs because an unbound text editor stores
a value as a string, therefore formatting cannot be applied.
If you use XtraEditors 3 or higher, you may wish to set the editor's
Mask.MaskType property to Numeric. In this case, the editor is forced
to handle the edit value as a number and, therefore, it can format it.
If you wish not to use the Numeric (or DateTime) mask, please use the
ParseEditValue event to convert a string to a number.
I can suggest you to use Numeric mask with n0 as edit mask:
To accomplish the above is fairly simple:
To only allow positive whole numbers, you need to set the MaskType to Numeric and use the EditMask ##########;. The number of # represents the possible number of didgets so ten times # means you can use a ten-digit number. (see nempoBu4's answer)
To show an additional ,00 when the control loses the focus, you simply need to set the DisplayFormat as FormatType = Numeric and FormatString = n2.
Suppose we inherit from WPF TextBox and then try to get text changes through overriding OnTextChanged.
Then we would notice when changes occurred, but the only information that we would have is:
Offset that this change occurred
Removed Length
Added Length
Can we get the accurate added text by using,
Text.Substring(Change.Offset, Change.AddedLength)
in OnTextChanged?
Text Change occurs in different conditions (such as user input, pasting text, or setting Text property in-code). Is there any possibility of conflicting changes coming into e.Changes?
Is this approach a trust way? If answer is No, Is there any other standard way(s) to get accurate changed text?
For a TextBox, this event occurs when its text changes; for a RichTextBox, this event occurs when any content or formatting changes (for example, images, table, or background color).
Can we get the accurate added text by using ... ?
Yes, you will always get accurate text in case of TextBox. You can make use of e.UndoAction to check for addition/deletion of text.
Read documentation here.
Is there any possibility of conflicting changes coming into e.Changes?
There won't be conflicting changes.
In general, the following will always be true:
The changes that occur result in the document being in a valid state.
The collection is ordered consecutively, related to where the change occurred in the control. For example, a TextChange object
that represents a change at position 2 is before a TextChange
object that represents a change at position 10.
Two TextChange objects do not represent an overlapping area. The value of Offset plus the value of AddedLength of one TextChange
object is always less than or equal to the value of Offset of the
next TextChange object in the collection. Likewise, the value of
Offset plus the value of RemovedLength of one TextChange object is
always less than or equal to the value of Offset of the next
TextChange object in the collection.
The collection reflects whatever changes occurred, even if there seems to be no net change. In the preceding example, neither the
first or fourth change results in a net change, because each simply
removed and re-added the and symbols, respectively. But
the symbols were actually removed and added, so they are included in
the collection.
More can be read here.
I made a short test program with one TextBox and one Label and I could not find the problems you describe. If I implement an TextChanged event for the TextBox like the following it works even if I paste something.The checking for null is needed because if the Textbox has an initial value the Initilialize method will trigger the change event before the label is created.
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
TextBox tbSource = (sender as TextBox);
if (lblOutput == null)
return;
lblOutput.Content = tbSource.Text;
}
Really simple question... how do I get the RibbonTextBox to accept the Return or Enter keys to enable multi line text input?
On a normal TextBox, I'd just set the TextBoxBase.AcceptsReturn Property to True to set a value that indicates how the text editing control responds when the user presses the ENTER key, but that doesn't seem to do anything on the RibbonTextBox.
Just to note, the related TextBoxBase.AcceptsTab Property also does not work on the RibbonTextBox, so it seems as though they have simply overlooked these properties when developing the RibbonTextBox.
Does anyone know if there is a work around, or will it simply not work?
In my propertygrid, I support an Hour value that converts a string like "8 AM" to an Hour object. There are only 24 possible values for them, but I don't want to restrict the user to using the drop down.
So the custom HourConverter : StringConverter implements GetStandardValues, but forces GetStandardValuesExclusive to false. I want the user to be able to type in the hour if they want to, but get an error if a mistake was made (ConvertFrom throws a FormatException).
Here is the problem: if the user enters an invalid value, the "Property Value Invalid" message box pops up as expected. But now, if I try to get the correct value through the drop down, the alert box comes up once when the drop down is triggered, and another 2-3 times after I've chosen a valid value from the list. It looks like when the drop down is created, ConvertFrom is called on all the string values in the list including the invalid one sitting in the text box.
What ends up happening is that if the value in the box is invalid, the user can't correct it at all by looking at the list, because that just pops up more messages no matter what is chosen, and nothing changes. How can I prevent this? Do I just have to set GetStandardValuesExclusive to return true?
I have code like this, in pagefunction making up a wizard:
<TextBox Name="txtDate" Text="{Binding Path=Date}"></TextBox>
The user types in and clicks next, object sent to next page with this data.
But if I set
<TextBox Name="txtDate" Text="{Binding Path=Date, TargetNullValue='2010-01-15'}"></TextBox>
So I can have some "example" text in the box already, and the user hits next to accept this without changing it, no value is passed in the object to the next pagefunction. If the user changes it then it works as usual.
So how can I have some default text without stopping the data being sent on?
You could set an initial value on the date that you are binding to.
If the Date property is a dependency property when you create it you can give it an inital value. Then you could attach a handler to notify you when it changed, and mark a flag as non intial value. (so you know its changed)
If you're providing a true data default (i.e. one that is a valid data value) consider initializing your data-bound object to that value.