I have a textbox inside a TabControl. The textbox binding has UpdateSourceTrigger=LostFocus. The textbox uses Attribute based validation from the data model. This validation is working correctly.
In the TabControl.SelectedItemChanged event I call modelObject.Validate() and prevent the switch to a different tab if an error occurs.
The problem I have is that the order of execution is backwards. The validate call occurs before the property setter. In the case of an invalid field I am able to switch away from the tab even though an error has been detected.
How do I get the order or these events ordered properly?
Is there a way to cancel TabControl.Items.CurrentChanging?
https://social.msdn.microsoft.com/Forums/vstudio/en-US/d8ac2677-b760-4388-a797-b39db84a7e0f/how-to-cancel-tabcontrolselectionchanged?forum=wpf
Seems to work by subscribing the CurrentChanging event. Can cancel tab changing action by setting the CurrentChangingEventArgs Cancel to true
WPF is definitely incorrect here. However, the fix is really simple.
In the SelectionChanged event handler call {whatever your tabcontrol is called}.Focus(). This immediately forces the lostfocus event for the textbox (which forces the setter to be fired) and solves the problem.
Related
In reference to this MSDN page (or any related page on the matter), it states that:
When you change the focus by using the keyboard, focus events occur in
the following order:
Enter
GotFocus
Leave
Validating
Validated
LostFocus
However, when you use the mouse to raise events, the order changes!
When you change the focus by using the mouse or by calling the Focus method, focus events occur in the following order:
Enter
GotFocus
LostFocus
Leave
Validating
Validated
Wouldn't this make the chain of events completely different? My interpretation here is that the keyboard chain ensures everything is in working order, then raises the LostFocus event. Yet, the mouse events seem to raise it before validating for some reason. Why is that?
As noted above:
In the MSDN article you linked worded strong enough? Never use LostFocus, only Leave.
The keyboard navigation must be in this order in order to apply the validations. Those are intended to react to them in order to validate any input strings.
The best example I can think of is the e.Cancel aspect in validation. Using the keyboard for navigation is usually a control to control type of navigation (including child and parent controls). Using the mouse for form navigation does not always result in a control being selected. For example closing a form or simply click outside of the control (i.e. re-positioning the form). It is not always desirable to have the validation occur when a mouse click occurs outside a control. Hope that helps.
I have a textbox in WPF and bind a command to its LostFocus event and do some validation in that command.
Now on the same window i have a Save button whose Key binding is Ctrl + S.
If a make some changes in textbox and then push Ctrl + S, it executes the save command without raising the Lost focus event on my textbox.
I know this is by design.
But i want to execute that piece of code before save command, i can't hardcode that code in save process, i want to execute it only when the focus is in textbox.
You need to factor the validation code out into a separate method that can be called by both the LostFocus and the Save command. Calling the LostFocus from the Save is a bad way of implementing this logic.
The new method can return a boolean to indicate whether the validation succeeded or not. There are better ways of doing validation that don't rely on binding a LostFocus command, check my blog post Taking data binding, validation and MVVM to the next level - part 1 for more ideas.
Even if I associate the button with a class derived from ICommand, I am still left with figuring out how the button should trigger the CanExecute method and refresh its enabled state. I do know about the CanExecuteChanged event for which a button with an associated command registers, but see the following paragraph for why this is troublesome.
On a plain old dialog consisting of some 10-15 controls, it seems haphazard to have to process every change notification for every single one of those controls, triggering the CanExecuteChanged event on the button's command, causing the button's enabled state to be affected by the CanExecute method's return value. Even stating what needs to be done in the last sentence was quite cumbersome.
There must be a better way of coding a WPF dialog, so that the confirmation button (e.g., OK) is grayed out until all controls have valid information and is enabled at that point in time (i.e., when all controls are properly filled in). Sample code, ideas and pointers to articles would be immensely appreciated.
Thanks
I don't see anything haphazard here. Since your condition is "all controls have valid information", this can occur after any control is edited, and therefore you need to listen to change notifications from all controls.
On a plain old dialog consisting of some 10-15 controls, it seems
haphazard to have to process every change notification for every
single one of those controls,
I don't think so. Every Textbox, checkbox changed event is handled by the same handler, say SetState(), which calculates the overall state of the dialog. Every time a control is edited, the entire state is recalculated.
until all controls have valid information
Then that object would have a boolean property EnableOKButton, let's say, which is set according to the updated state. Then that property is bound to the button's Enabled property so it automagically changes - without dealing with extraneous events.
I'm currently updating it on click, but this results in the user being able to see the repopulation occur. Which other event can I use which will allow me to handle it myself, then show the combobox when i'm ready? ( after population)
I don't know what you're developing, but that combobox is probably on a window or so that will have an event that fires on show. Use that event to populate the combobox in.
[edit] Ah Winforms. Use the Load event.
[edit2] On each click eh.
Alright. I found a dirty solutions that advises you to override the WndProc and capture messages, but I think it's better to inherit the combobox and override OnDropDown to perform you populating before calling the ancestor's OnDropDown method.
You should populate the box when entered too, because a value may be selected using the keyboard (arrows) without even dropping down the box. You'll need both if you want it on each selection, because a click only causes the Enter event when the box didn't have focus before.
Have you tried the ComboBox.DropDown Event?
You could try to call SuspendLayout() before updating and calling ResumeLayout() after the changes.
combobox.add_HandleCreated triggers after the control is created as the form is loading
I have a textbox bound to a datasource. The textbox's TextChanged event updates another textbox.
The problem is, I do not want the first textbox to show, so I set its Visible property to false.
However, now the TextChanged event does not fire!
I can work around it by setting Visible=True, Left=-100000 on form load, but I'd like a proper solution.
Can anyone offer an explanation?
Set your textbox.Visible = false in the FormLoad event instead of in the designer. It has to do with handle creation. If the textbox is not visible during construction, then the handle is not created. If the textbox is made invisible after construction, then the handle will have been created and events will occur.
See this discussion on MSDN.
An alternative solution to the accepted answer is to set up the TextChanged listener on Loaded, this works for me just the same (in Silverlight at least) and keeps the designer view as it should be.
What type of datasource is it? It might have an event that you can use directly instead of using a textbox to listen for an update.
If Visible is equal to false then the Control is not rendered. Therefore it will be unable to fire an event.
Instead, set the style to display:none. You can set/unset this programmatically using the Attributes collection:
MyTextBox.Attributes.Add("style", "display: none");