C# "Textchanged" event and infinite loop? - loops

I'm currently creating an application that has three textboxes. Typing into one box will result in the other two having "converted" versions of the text displayed. All three boxes can be typed into and serve the same purpose (though provide different outputs for the conversion).
The "TextChanged" event is called whenever the text value of the box is changed, that is fairly self-explanatory. But will this event also trigger if I change the value through code.
Say if I changed the first box, it would create text in the second. Would the second box trigger the event as well? And would this result in an infinite loop?

No, it wouldn't. Text taken from the MSDN page on the event:
The TextChanged event is raised when the content of the text box changes between posts to the server. The event is only raised if the text is changed by the user; the event is not raised if the text is changed programmatically.
MSDN page

Yes, or no.
this behavior differs from Winform and ASP.Net (each corresponding to System.Windows.Forms.TextBox and System.Web.UI.WebControls.TextBox), means that if you are to create ASP.Net application then the answer is no, but if you are working on Winform application then the answer is yes.
Please refer to the following different saying from the MSDN:
System.Windows.Forms.Control.TextChanged Event
Remarks
This event is raised if the Text property is changed by either a
programmatic modification or user interaction.
For more information about handling events, see Handling and Raising
Events.
System.Web.UI.WebControls.TextBox.TextChanged Event
The TextChanged event is raised when the content of the text box
changes between posts to the server. The event is only raised if the
text is changed by the user; the event is not raised if the text is
changed programmatically.

Related

BindingNavigator events not raised

I have an "odd" situation.
I've got a form with a binding source and a binding navigator.
In this instance, I've got 161 records (via EF6) to display.
The databinding to the controls works nicely.
But what I find is that the expected events for the binding navigator don't happen consistently. Then they settle down.
I've got event handlers (additional to the default ones, but the same thing happens when I remove the default ones as well)
I set the binding source one the navigator, and the "Position Changed" event is raised (as I'd expect)
Clicking on any of the "Move" buttons, or editing the position field will result in:
No event being raised (not the item click events, not the binding source Position Changed) roughly 3 out of 4 times.
Then the event raises, all the expected navigation occurs, and repeat.
But it doesn't seem to be permanent, because after a while almost all the records have the navigation all starts working properly.
This happens with and without the debugger connected.
The other thing I notice is that when it fails, the icon in the taskbar flashes once.
It's not something in any of my handler code, because it never gets to my code.
It might be a property setting.
It's not an exception, because even with "break on all exceptions", no exception is reported.
When you talk about "move" buttons, I take it that you mean the next/previous record navigation buttons on the BindingNavigator. Those buttons are not full-fledged Windows controls, but rather they are "lightweight" controls. I've seen issues in the past because of this.
While I do not have all the details fresh in memory, it had to do with the fact that they don't steal the focus away from other controls as regular Windows controls do, and this caused some events to not be raised.
I suggest you create your own navigation buttons, which is what I ended up doing on all my Windows Forms project. Those regular buttons can then call the BindingSource methods such as MoveNext and so on.

How can I intercept the text to be inserted into a RichTextBox?

There is a TextChanged event for the RichTextBox, what I require is a TextChanging event so I have chance to perform an action before the text is changed. The KeyDown event is not enough as my application uses a speech recognition engine which means it is possible to enter text without using the keyboard.
I was hoping I could intercept something in the WndProc method but nothing stands out.
Any ideas or help would be much appreciated. Thanks.
Try using the TextChanged Event from the RichTextBox class. Based on the description from MSDN
This event is raised if the Text property is changed by either a programmatic modification or user interaction.
It should be able to handle what you are trying to do.
Edit: You could have some sort of intermediary storage of the text so that when the text changes it is stored somewhere else first and after the text changed event is done, you can put the text back into the RichTextBox. But without knowing specifically what you are trying to accomplish, this would be my recommendation.

Is there any event before source is updated in binding in WPF?

I am looking for something that fire before the source is update
So instead of Binding.SourceUpdated I want Binding.PreviewSourceUpdated
I think you would need to handle this on your UI element and intercept the event if it's not ideal. So for example say you had a text box and a user pressed a key. You would use the PreviewTextInput (or similar preview) to see if you wanted the data changed - then mark the event has handled if you didn't.
The only other option that I know of is to use DataValidation and not allow the property to be updated for the model side.

Databinding falls behind event notification - discussion

Found an interesting problem that I first found in WinForms, and found again in Silverlight, and more than likely WPF as well when it comes to databinding.
I have a tab control with several tabs. As users click across the tabs, each time should be valid before allowing the user to switch from the tab.
For example, user is in a text box which is updated. Binding of text boxes is not flushed until the control loses focus. Loss of focus occurs when the cursor is moved from the control, and focus is given to another control.
In this scenario, the user tabs into a control (let's use text box for this example), and updates the text box. At this point the databinding has not flushed the control, and hence the VM has not yet seen the change. The user then uses their mouse to click the next tab of the control.
At this point things get interesting. I used the PreviewSelectionChanged (Telerik RadTabControl), as I want to check things out before the jump to the next tab occurs, and it also gives me the ability to cancel the event.
However, when I look at the VM, in this event, it still does not have the updated data. I see the VM is clean, and go ahead and allow the jump to the next tab.
As soon as this event is over however, the databindings flush, and the VM gets updated. what now? The events are out of sync! When the mouse was used to click the next tab, the textbox should have lost focus, flushed it's bindings, before the Preview of the Tab click! It's to late to jump back and say oops we didn't catch that in time!
I think I found an interesting work around to this issue - but I'm not 100% sure it will work 100% of the time. I cancel the current event, but then I use the Dispatcher and create a delegate pointing to another method with the same signature as the current event. The Dispatcher will add this message to the message pump, which by this time will now (hopefully?) be behind the messages of the VM updating...
My two questions are:
1) I'm assuming that the textbox control either didn't flush when the mouse left the control, or the process that was fired was too slow and hence the preview message was on the pump before the databinding - either way I see this to be a major issue.
2) Is the workaround a good solution?
Ok, first to answer question 1:
Just because the mouse left the textbox area, doesn't mean that the textbox lost focus. It only loses focus once something else gets focus. For example, if you moved the mouse out of the textbox and click on some other control on your page (it can be anything from a scroll viewer to another textbox, etc.) then your textbox will lose focus.
Now, based on that, the events do not happen in the wrong order. What happens is; your click event on the other tab triggers both the textbox to lose focus (and the data binding to take place) and the move to the next frame, and based on that, you basically get a race condition where the moving to the next tab happens before the databinding takes place.
About question 2:
What you can do is, set the UpdateSourceTrigger to Explicit, you will however be forced to then have some kind of text_changed event and manually update the binding.
You can read more about that here. It might not be the most complete explanation but is a good place to start.
On the other hand, you can associate some events to the textbox and force the textbox to lose focus on those events (e.g. mouse out).
Just an idea: Why not do everything in the VM's PropertyChanged event?
protected override void OnThisViewModelPropertyChanged(object sender, PropertyChangedEventArgs e) {
if(e.PropertyName == "WhateverProperty") {
//Do your magic here for whatever you want to set
}
}
Have your TabItems bound to a collection that will control is being disabled or not.
<sdk:TabControl>
<sdk:TabItem IsEnabled="{Binding SomeProperty, Converter={AmIDisabledOrWhatConverter}}" />
</sdk:TabControl>
That way, everything is triggered whenever a property is chaned in the vm. No more timing issues since everything is on the vm.
Just my two cents.
There's a design defect here, and you're trying to work around the defect instead of fixing it. You shouldn't have to figure out how to cancel the Click event on the tab. The tab shouldn't be processing Click events in the first place.
Generally speaking, if it's not legal for the user to click on a control, the control shouldn't be enabled. The tab should be disabled until the state of the view model is valid.
Your view model should be exposing a command for navigating to the next tab, and the tab should be bound to the command. The command's CanExecute method should only return true when the state of the view model on the current tab is valid.
This doesn't fix your other problem, which is that Silverlight doesn't support UpdateSourceTrigger="PropertyChanged" out of the box. But that's a solved problem (here is one example).
Note that if you implement commands to handle this wizard-like navigation in your application, you can, down the road, change the view to use something other than a tab control (e.g. to use navigation buttons like an actual wizard, or something like Telerik's PanelBar) without having to screw around with event handlers.
Change your bindings to include UpdateSourceTrigger="PropertyChanged".
This will ensure that your data sources are updated on every key stroke, not just LostFocus.
MyOwnTextBox()
{
this.TextChanged += (s, e) => UpdateText();
}
private void UpdateText()
{
BindingExpression be = GetBindingExpression(TextProperty);
if (be != null && be.ParentBinding.Mode == BindingModes.TwoWay)
{
be.UpdateSource();
}
}
I am using this class it updates my binding on the fly, however there is issue with empty string and null values, if your destination property is nullable string then this will update empty string in your destination property. You can get workaround by using some sort of string converter which will use null instead of empty string in case of nullable strings.

Which event should be used to update a Model from TextBox (LostFocus, LostKeyboardFocus, etc) in WPF? How to set precedence of events in WPF?

I have an application in which there are lot of TextBoxes and some Buttons like Save, SaveAs,etc.
When the user edits a TextBox, I have to check the DataBase for some range, validate the range and update the DataBase.
If there is any error in value entered by user,then I should not allow the TextBox to lose focus.
I was using LostFocus event for this and it was working fine until lately I discovered a bug in my application.
Bug : The user edits a value in TextBox and then clicks on Save button; the LostFocus event is not called and so Database is not getting updated :(
Now my question is which event should I use in TextBox to update the DataBase. I tried TextChanged event but it validates for every character and making my application slow. I am confused in chosing the right event for this kind of application!
Note :** The Buttons are in different UserControl !
EDIT 1 : I have some Commands attached to click of Buttons, these Commands are getting executed before LostFocus !! Can I set precedence or something like attached behaviours or commands should get executed after LostFocus !!
EDIT 2 : I was just debugging the application by disabling some commands, what I found was in some cases, the DelegateCommand gets executed before LostFocus, so I want to avoid that. How can I go about it ? I felt during development its impossible to developa pure MVVM application so I am kind of using a bit of codebehind !
Trapping the keyboard focus within a control is usually a sign of bad UI design - it's pretty user-hostile to force the user to fix data in a control before he can type anywhere else in the UI.
That said, you shouldn't be using events at all here. You're trying to write a Windows Forms application in WPF. You should write a WPF application.
Create a class that is a logical model of your view - i.e., there's a string property for the text box and a Command property (or, more likely, a RelayCommand) for the Save button. Bind the text box to the string property, e.g.:
<TextBox Text="{Binding MyTextProperty, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
Because the UpdateSourceTrigger is PropertyChanged, the source object will get updated every time the user types a character.
Bind the button to the command property, e.g.:
<Button CommandBinding="{Binding SaveCommand}">Save</Button>
Implement the appropriate CanSave and Save methods that the RelayCommand (as described in Josh Smith's essential article on the MVVM pattern) requires, so that the button is enabled when the string property is valid and disabled when it's not.
I think the best approach is preventing a user to proceed until all valid information has been gathered.
Just like an installation wizard with Terms & Conditions Dialog and Next button. Until you check the I Agree checkbox, Next button is disabled.
This way, you don't have to worry about user proceeding without providing valid information. This way, you can use any event on TextBox to validate your data.

Resources