TwoWay binding is not really Two Way? - c#

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.

Related

Cursor misbehaving in UWP TextBox

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.

TextBox TextChanged Event Problems

I'm using a basic TextBox that is bound to an object. Basically, what I want to do is call a method every time the text in the box is edited and the user de-selects the box or when the underlying bound data is edited. What I am using right now is the TextChanged event, but this has a few problems:
It is called when the TextBox is first created, and I don't want this.
It is called every time a new character is added, and I only want it called when the underlying bound data is changed (which seems to be whenever focus shifts from the box).
How can I accomplish this?
EDIT: I've tried several other TextBox properties like Get/LostFocus but they never seem to fire.
Also, I don't want to put this method call in the Setter of the Property, because the underlying data is something that is logically separate from the UI of this project and I don't want any method calls that relate to doing computations for the UI.
The event LostFocus fires when the focus is shifted from the current element. I tried it and its working fine.
As jods says, the best way to bind your TextBox's Text to ViewModel's property. The Code are:
View:
<TextBox x:Name="TextBox1" Text="{Binding Path=Text1,Mode=TwoWay, UpdateSourceTrigger=LostFocus}"/>
ViewModel:
public string Text1
{
get { return _text1; }
set
{
_text1 = value;
RaisePropertyChanged("Text1");
}
}
View code behind:
private void ViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Text1")
{
//Call UI related method...
}
}
In this way, it satisfy your two conditions:
1. Every time when you edit TextBox and lose the focus, Setter of Text1 will be called and ViewModel will raise PropertyChanged event.
2. When underlying Text1 is changed. Text1 will also raise the event so View can know it.
Also it can avoid your two concerns:
1. In the first time binding, only getter of Text1 is called. No event is raised.
2. Setter of Text1 is only called after TextBox is lost focus.
every time the text in the box is edited and the user de-selects the box
Hmmm AFAIK it's a standard behaviour of TextBox if you bind text like that: Text={Binding Property}
when the underlying bound data is edited
You can provide this functionality inside setter of your property.
Best design is to listen for changes in the underlying bound property. You can do that without changing the setter if you use a DependencyProperty or if your object implements INotifyPropertyChanged.
When the underlying property changes (LostFocus by default, or each char at a time) is a binding option.
If you don't want to follow my advice of listenning for changes in your (view-)model, you could subscribe to GotFocus and LostFocus events. Save the current value when you get focus, compare with current value when you lose it. If it's different -> do what it is you want to do.
I am not sure what you are finally trying to achieve but I am going to take a guess at this. If you are following an MVVM pattern then, then it seems like you can achieve what you want by using the updateSourceTrigger property of the binding. If you are not using MVVM then you might what to take a look at using MVVM

Caliburn Micro: Disable button on form validation error

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.

C# How to commit a TextBox?

In a form, I have a TextBox Binding an Object on its member property "Title". Along with it is a "Save" button to test the binding.
Seems like the underlying object property does not get updated unless the textbox loses focus. But there no form.ActiveControl.Blur() for use. Besides, this does not seem like a sound hack.
Anyway to do this better? Thanks.
EDIT: Sorry for not being clear. My question is in the title: "How to commit a TextBox". I use the term "commit" from the DataGridView commit and BindingSource commit. And it's in WinForms. (Have never worked with WPF, so it didn't occur to me. Sorry).
The actual scenario I have is I have a bunch of TextBox binded to property of a single Object. The user enters values in all the TextBox and when the user clicks save (toolbar button), the last TextBox is still in focus (or in editing mode) hence the save will not capture the last value in the last textbox.
I want to find the correct way to "commit" the textbox value just before saving.
Thanks.
Since the question has been updated to indicate this is WinForms, you'll need to handle things a little differently than if this were a WPF application. Fortunately, it turns out that the solution is very simple.
Whenever the user clicks on the "Save" button (so, say, in your Save button's Click event handler), you need to call the EndEdit method on your BindingSource. This will cause all pending changes to be committed to the underlying data source, exactly what you were hoping to accomplish.
Also see the relevant documentation on MSDN for more details.
Sounds like WPF from the problem description..
You want to change the binding so that it updates when the property value changes instead of when the textbox loses focus (which is the default when binding to TextBox.Text). You can do this by setting the UpdateSourceTrigger property on your binding:
<TextBox Text="{Binding UpdateSourceTrigger=PropertyChanged}"/>

C#: TextChanged event of a Control not firing on "assign"

Ok, here's the deal.
I have a graph, that "listens" to some labels' textfields, and graphs their values. It does this by adding the values on the TextChanged event.
The problem:
TextChanged only fires when the text has actually changed (obviously), and not when it has been assigned a new value.
What I need:
A way to detect if the Text field of label has been updated (assigned to), and all I have to work with is a reference to the Control (ie the Label).
I realize TextChanged wasn't designed for this, which is why I'm wondering if any of you guys have encountered a similar problem, and found a solution to it.
The reason that your TextChanged event handler is not invoked in initial assignment of the text is that it is attached after the first text has been assigned (the designer seems to do things in this order by default). I would do like this:
TextChanged calls another method (UpdateGraph)
UpdateGraph collects necessary data and updates the graph
Call UpdateGraph as the last thing done when loading the form
That will make sure that the graph is updated with the initial values. It is important that this call happens after the call to InitializeComponent.
It is fairly common practice in "setters" to ignore trivial changes, for example:
public int Foo {
get {return foo;}
set {
if(foo != value) {
foo = value;
OnFooChanged();
}
}
}
If Text is behaving like this, and you are relying on all updates causing an event, then it may not work as you want. I would probably try to find another way to do what you want; perhaps using an intermediate object that passes the values through.
You could create your own control that inherits from that control and create your own Text property that will fire an event when assigned a new value.

Categories