WPF TextBox reacting weirdly with stringformat 0:N2 - c#

This is hard to explain so please look at the WPF gif below -
I have a textbox with a stringformat {0:N2} and bound to a property.
There are two problems here -
(1) When hitting the decimal key, another decimal is added.
(2) During backspace, after deleting the decimal digits - the caret doesn't jump over the decimal rather starts adding '00' to the number itself.
I did a workaround for point (1) -
private void TextBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Decimal)
{
e.Handled = true;
((TextBox)sender).CaretIndex += 1;
}
}
If there is a better way to handle such things in application - please do let me know.
Now, how do I handle the second problem? The workaround Im trying to implement is - if decimal point reached, handle the key press and move the caret position. Not sure if this is a good solution and if so, how to know when I have reached the decimal point?
Comparing the caret index to the length of the textbox value just to know if it has reached the decimal point seems like overdoing it. What is the correct solution to these 2 problems?

The problem is due to when the stringformat is being applied to the value.
Which is as the value comes back from the binding Source ( the bound string property ) to the TextBox Text ( the Target ).
And it's linked to metadata of textpropety.
The Textbox TextProperty binds twoway, this is set in the metadata of that dependency property.
The default behaviour of a textbox is to copy the value to the bound source when the control loses focus.
If you use that then the n2 format is applied once the user has finished editing. They may fix up whatever they like with the zeroes and decimal point and the format only gets applied when they tab away.
By contrast, if you set UpdateSourceTrigger="PropertyChanged" in your binding then you will find it behaves weirdly. This is because the user types a letter, the whole value is transferred to the bound property which notifies the control it changed.
All sorts of weird bad things happen as the formatting is being applied.
It's possible that this is an edge case whoever built the textbox didn't consider.

Related

Label displays punctuation incorrectly with RightToLeft

I'm trying to learn C# and .NET by creating a calculator app. However, I'm seeing some weird behavior with WinForms label and punctuation. My app has a series of number buttons, a "period" button for decimals, and various operators. When you press a button, I add the value to the label that is displaying the value:
displayLbl.Text += selectedButton.Text;
or
displayLbl.Text += ".";
The label has RightToLeft set to "true" to mimic the display of a typical calculator.
However, when a period first appears in the label, it appears ahead of the rest of the numbers that were added before it. For example, it will look like ".456" even though the "456" was added earlier. As soon as you add another number, the period will then appear back in its right place like "456.7".
This also happens with the negative sign (-). If you add "-478" to the label, it will appear as "478-".
This seems really buggy. Is there any way to fix this?
I set RightToLeft to "No" and then did the following and it worked beautifully:
this.displayLbl.TextAlign = System.Drawing.ContentAlignment.MiddleRight;

Devexpress RegEx Mask with different Displayformat doesn't work

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.

How to find WPF TextBox's changed text?

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;
}

Setting the Default Value for Decimal Property in WPF Binding

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.

Conditional prevention of the textbox change

I have a TextBox, and a TextBlock within the Border. The TextBlock's Text property is bound to TextBox's value. When I type into the TextBox, the Border changes its width according to the TextBlock's new size.
There is an event handler for TextBox.TextChanged in which I test whether the size of the border exceeds a certain number. If it does, I want to prevent the TextBox from making the change that caused the handler.
If a character was always added to an end, I would be able just to substring the text, but all other sorts of changing can occur, for example pasting a large amount of text into the TextBox.
So, what would be the way of preventing the change from the handler? I remember in some WindowsForms e.Cancel property which when set would ignore the action, but haven't seen that in WPF and the TextChangedEventArgs obviously does not have one.
Thanks
You can listen to the PreviewTextInput event and set e.Handled to true to prevent the change from taking effect.

Categories

Resources