WinForms firing Enter event twice - c#

I've got the following:
private void fooForm_Enter( object sender, EventArgs e )
{
FooBar()
}
private void FooBar()
{
Console.Out.WriteLine( "Foo" );
/*
do stuff
*/
OtherControl.Focus();
}
The problem I'm experiencing here is that I get to see the text in the console twice, even though I only put focus on the fooForm once. However, if I comment out the OtherControl.focus() line, FooBar will only be called once. (No, OtherControl is not the same object as fooForm.)
What causes this and what can I do to make sure FooBar is only called once?

According to the MSDN Documentation:
Do not attempt to set focus from within the Enter, GotFocus, Leave, LostFocus, Validating, or Validated event handlers. Doing so can cause your application or the operating system to stop responding.
You appear to be doing just that.

As from MSDN:
The Enter and Leave events are hierarchical and will cascade up and down the parent chain until the appropriate control is reached.
Thus, your fooForm receives Enter event for its children too.
Also notice, from the same MSDN article:
Do not attempt to set focus from within the Enter, GotFocus, Leave, LostFocus, Validating, or Validated event handlers. Doing so can cause your application or the operating system to stop responding.

I did a bit more googling and found a good solution to achieve the functionality I wanted without setting the focus in those events as per the solution here: Alternative to set focus from within the Enter event

Related

How to get notified after the event ends

In my UWP app I am using DynamicOverflowItemsChanging event of a CommandBar my usecase is not very complex, I tried to solve another problem I had by using this event, see the answer of this post.
So as shown in the answer in the link I provided above, I am trying to invoke this event and sync the visibility of MoreButton now the problem is this event is fired when the secondary overflow menu of command bar doesn't have the item removed or added yet, so they still show the items which they had before the event was fired, but when this event is completed then transfer of items is also completed.
So in short I want to raise another event somehow or get notified when the DynamicOverflowItemsChanging completes its execution, so I can have the correct data and set the visibility of more button correctly. or in other words I want to implement a behaviour of DynamicOverflowItemsChanged event, which unfortunately doesn't exist in the api, so I am looking for an alternative way.
I know I can invoke another event right at the end (just before DynamicOverflowItemsChanging event is finished), but that way I still don't get the correct values, correct values only become available when this event finishes its execution. Like we can do with Task.Then() so when a task completes another can automatically start, so I want something like that here . any suggestions would be appreciated.
protected override void OnApplyTemplate()
{
var barr = (CommandBar)GetTemplateChild("MediaControlsCommandBar");
//the event to control the dynamicoverflow automatically.
barr.DynamicOverflowItemsChanging += (s, e) =>
{
if (_secondarycontrols.Items.Count == 0 && e.Action == CommandBarDynamicOverflowAction.AddingToOverflow)
_moreButton.Visibility = Visibility.Visible;
else if (_secondarycontrols.Items.Count == 1 && e.Action == CommandBarDynamicOverflowAction.RemovingFromOverflow)
_moreButton.Visibility = Visibility.Collapsed;
};//when this event finishes here I want to get notified.
//base implementation
base.OnApplyTemplate();
}
Warm greetings, fellow Microsoft Student Partner :-) .
The quick and dirty hack would be to add a Task.Delay to the end of the handler and hope the items will have changed until the delay is over. This is of course really ugly and error prone. I would suggest a different solution.
You already have access to the _secondarycontrols which is a CommandBarOverflowPresenter. This is very useful, because Items property has a VectorChanged event which is fired whenever an item is added, removed or changed. This means, you can actually use this event and move your logic inside it instead of using the DynamicOverflowItemsChanging event. You can then directly check for the number of items which will be accurate.

Win32Exception - error creating window handle?

Can you explain why this happens? Here are steps to reproduce the exception:
Drag-n-drop a TextBox on a form. Add any other focusable control such as a button on the form.
Add 2 event handlers for that TextBox as follow:
private void textBox_GotFocus(object sender, EventArgs e){
((TextBox)sender).HideSelection = false; //<-- exception highlighted at here.
}
private void textBox_LostFocus(object sender, EventArgs e){
((TextBox)sender).HideSelection = true;
}
Run the form and first click on the textBox, then click on the button then click on the textBox again, and the exception will throw: "Win32Exception - error creating window handle".
The code is simply to make the HideSelection change accordingly when the textBox gets focused and loses focus.
UPDATE
I don't know why is so volatile, I created another project and now the problem is different, there is no exception but an indefinite loop which makes the textbox flicker, the form doesn't seem to responsive, the CPU usage is consumed up to about 17-20%. The last demo is still opened and that demo still has the Win32Exception thrown. Not a clue at all. Now the code of the two projects are the same but the problems are different.
Well, there are a couple of things to note.
First of all, HideSelection doesn't hide or unhide the selection. It specifies, whether the selection will be hidden (or not) when the control loses focus. So it's pointless to change it when the TextBox becomes focus'ed.
What you're doing in LostFocus is default, btw. Why there is an exception in GotFocus is burried within Windows API, I guess. Maybe some undefined state when HideSelection checks inside a focus changed event whether the TextBox has focus or not or tries to hide the selection which is not shown.
Edit: It's not the Windows API on the first hand, but the framework. It tries to "recreate the handle" in the setter of HideSelection if it is changed (don't know why yet - would have to analyse sources) and seems to fail (don't know why either).
Edit2: Finally there's some problem in Win32 DestroyWindow - which leads to skipping the creation of the new window. Maybe because the old one is "in use" in the focus change events?
Interestingly, as soon as the exception occurs (for me), the LostFocus event is fired, immediately followed by GotFocus which throws another exception a.s.o. thus blocking the GUI. Both assignments to HideSelection throw the exception.
Also, when you click the TextBox, any selection is deselected automatically. This, however, is not the reason for the problem, because the exception is thrown if you change focus by pressing Tab (whose normal behaviour is to restore focus). But it may be related (state problems).
If you actually want to restore the selection, you could do it like this:
int selStart;
int selLen;
void textBox1_LostFocus(object sender, EventArgs e)
{
selStart = textBox1.SelectionStart;
selLen = textBox1.SelectionLength;
}
void textBox1_GotFocus(object sender, EventArgs e)
{
BeginInvoke((Action)(() =>
{
textBox1.SelectionStart = selStart;
textBox1.SelectionLength = selLen;
}));
}
I repro this crash. You can easily see it going wrong by setting breakpoints on your event handlers, note how they fire over and over again before your program bombs. The explanation is a bit long winded, I'll give the short version first. The MSDN documentation for the LostFocus event gives stern warnings, both a Note and a Caution, pointing out that this is a low-level event that is dangerous. These events are also hidden in the Properties window for that reason. Fix your problem by using the Enter and Leave event instead.
The long version: the TextBox.HideSelection property is rather special. It is related to the way some properties on native Windows controls are specified. These controls are created with the CreateWindowEx() winapi function, it takes a dwExStyle and dwStyle argument, flags that specify style options for the window. The HideSelection property is such a style flag, ES_NOHIDESEL.
That presents a problem when you want to change the property. Difficult because it can only be specified when the native control is created. Winforms does something pretty heroic to deal with that limitation, it destroys the native control and re-creates it.
That can have pretty interesting side effects, to put it mildly. Most are not observable, but you do for example see the window on the screen getting destroyed and recreated. That's why it flickers. The core problem with your code is, inevitably, because the native window is getting destroyed it also loses the focus. So the LostFocus event immediately fires, right after you got the GotFocus event. Which does something unfortunate, it again changes the HideSelection property. Which forces Winforms to recreate the native control again.
This repeats over and over again when your GotFocus event handler yet again runs for the new native control. This does eventually end when Windows puts a stop to it and doesn't allow any more native windows to be created, it pulls the plug at 10,000 controls after a while. Which generates the "Error creating window handle" exception.
The Enter and Leave events should always be used for focusing events, they only fire if the user actually moved the focus, and don't fire when it happened because of other reasons, like this one. Also notable is that there's no point at all in changing the HideSelection property like you do, the property only has an affect when TextBox doesn't have the focus. The selection is never hidden when it has the focus. So the proper fix here is remove these event handlers and simply set the HideSelection property to True in the Properties window. The default value.
Cant reproduce this works for me:
private void textBox1_Leave(object sender, EventArgs e)
{
((TextBox)sender).HideSelection = false;
}
private void textBox1_Enter(object sender, EventArgs e)
{
((TextBox)sender).HideSelection = true;
}

How to check whether text input is finished

I'm developing a simple WPF application where I want to use the text changed method for a specific text field. the thing is I implemented the method but, the method gets fired in very short period, like even after i enter one character. I want to check whether the text change is completed in order to go with the methods written in the text changed method.
private void searchBox_TextChanged(object sender, TextChangedEventArgs e)
{
if (...) // how to check whether the typing is finished?
{
// code goes here
}
}
I think you'll need the LostFocus event for this. As #SLaks comment says, you can't predict whether the user will press another key. Alternatively, you could databind the control - depending on what you're actually trying to do that may make more sense.
Instead of TextChanged, try monitoring the LostFocus event, which will fire when the user has left the textbox, either through pressing Enter/Tab or clicking somewhere else on the form.
Agree with LostFocus
UIElement.LostFocus Event
Question does not ask about binding but something to consider.
In binding the equivalent is UpdateSourceTrigger="LostFocus"
Binding.UpdateSourceTrigger Property
With binding you can get into more advanced validation UI effects.
How to: Implement Binding Validation

How can a control handle a Mouse click outside of that control?

I'm writing a custom control and I'd like the control to switch from an editing state to it's normal state when a user clicks off of the control. I'm handling the LostFocus event and that helps when a user tabs away or if they click on to another control that's Focusable. But if they don't click on something Focusable, it won't switch out of it's editing state. So I have two solutions in mind:
Walk up the tree to the top most element when it goes in to an editing state and add a handler for MouseDownEvent (and handle "handled" events). In the handler I'd kick the control out of it's editing state and remove the handler from the top most element. This seems like a bit of a hack, but it would probably work well.
Example code:
private void RegisterTopMostParentMouseClickEvent()
{
_topMostParent = this.FindLastVisualAncestor<FrameworkElement>();
if ( _topMostParent == null )
return;
_topMostParent.AddHandler( Mouse.MouseDownEvent, new MouseButtonEventHandler( CustomControlMouseDownEvent ), true );
}
private void UnRegisterTopMostParentMouseClickEvent()
{
if ( _topMostParent == null )
return;
_topMostParent.RemoveHandler( Mouse.MouseDownEvent, new MouseButtonEventHandler( CustomControlMouseDownEvent ) );
_topMostParent = null;
}
Use Mouse.PreviewMouseDownOutsideCapturedElement and add a handler to my control. In the handler I'd kick the control out of it's editing state. But I don't seem to get the event to fire. When does the Mouse.PreviewMouseDownOutsideCapturedElement get kicked off?
Example code:
AddHandler( Mouse.PreviewMouseDownOutsideCapturedElementEvent, new MouseButtonEventHandler( EditableTextBlockPreviewMouseDownOutsideCapturedElementEvent ), true );
Just to clarify the answer provided about mouse focus - it was useful but I had to do some further digging + mucking about to get something that actually worked:
I was trying to implement something like a combobox and needed similar behaviour - to get the drop down to disapear when clicking on something else, without the control having knowledge of what something else was.
I had the following event for a drop down button:
private void ClickButton(object sender, RoutedEventArgs routedEventArgs)
{
//do stuff (eg activate drop down)
Mouse.Capture(this, CaptureMode.SubTree);
AddHandler();
}
The CaptureMode.SubTree means you only get events that are outside the control and any mouse activity in the control is passed through to things as normal. You dont have the option to provide this Enum in UIElement's CaptureMouse, this means you will get calls to HandleClickOutsideOfControl INSTEAD of calls to any child controls or other handlers within the control. This is the case even if you dont subscribe to the events they are using - full Mouse capture is a bit too much!
private void AddHandler()
{
AddHandler(Mouse.PreviewMouseDownOutsideCapturedElementEvent, new MouseButtonEventHandler(HandleClickOutsideOfControl), true);
}
You would also need to hang on to + remove the handler at the appropriate points but I've left that out here for the sake of clarity/brevity.
Finally in the handler you need to release the capture again.
private void HandleClickOutsideOfControl(object sender, MouseButtonEventArgs e)
{
//do stuff (eg close drop down)
ReleaseMouseCapture();
}
Capture the mouse.
When an object captures the mouse, all mouse related events are treated as if the object with mouse capture perform the event, even if the mouse pointer is over another object.
I usually get the parent window and add a preview handler, even if already handled. Sometimes when MouseCapture is not enough, this technique comes handy:
Window.GetWindow(this).AddHandler
(
UIElement.MouseDownEvent,
(MouseButtonEventHandler)TextBox_PreviewMouseDown,
true
);
I would approach this a different way - have the form that contains the control remove focus from the control when a user clicks on another part of the form.
Having the control actually loose focus is far cleaner than attempting to have the control "simulate" focus being lost in certain situations, when in fact it hasn't. Bear in mind that unless the control has really lost focus it will still accept things like keyboard input.

How to force control to fire leave event in winforms using c#?

I am pasting text in textbox1.text and I need textbox1 should fire its leave event by itself.
For now I am using this following code. but i will appreciate if anyone can suggest me an elegant or better way:-
private void event()
{
textbox1.Text = SearchedText;
textbox1.Focus();
textbox2.Focus();
}
First I am pasting text, then setting up Focus on the control, then set up focus again on second control. It is firing leave event of textbox1, but any thing better?
Just call the code directly, no need to wait for an event:
private void textBox1_Leave(object sender, EventArgs e) {
mumble();
}
private void someEvent() {
textBox1.Text = SearchedText;
mumble();
}
void mumble() {
// etc...
}
Just calling textBox1_Leave(this, EventArgs.Empty) works fine too.
You should handle the TextChanged or Validated events instead of the Leave event.
To FORCE Leave, Validating and so on Events, no matter what, I've found ONE working solution.
First i tried:
ProcessTabStop(true);
ProcessTabStop(false);
instead of:
textbox1.Focus();
textbox2.Focus();
Problem with the TextBox 1 and 2 Focus() is that its only Active Component that needs Leave, Validating and so on fired, not other Controls, and besides, what if the form is dynamic, you as a programmer not necessarily have any idea what Control you are trying to Leave, that's why i changed Control.Focus() method to ProcessTabStop method above. The problem is then, if only ONE Control has TabStop true, there is no control to go to and back from. So Events are NOT Fired.
Next problem is that i not necessarily Close the Form with the mouse so Focus doesn't change, I use a Key (Ctrl+Enter) to Accept the Form, and then Leave, validating and so on are NOT fired, when i Send Form Close, as Form Close registers weather there are changes or not. But Values are set in Leave on TextBoxes, so I had to find a solution that worked no matter what i did to it. I almost gave up, actually i had a problem report all filled out, when I thought, what if i set ActiveControl to Null and then to the Control it came from. It worked, but had som "Flicker" due to color change on Parent Panel depending on Active or Inactive.
The "Workaround" that works in all cases is:
Control Old = ActiveControl;
// ActiveControl.SuspendLayout();
// ActiveControl.FindForm().SuspendLayout();
ActiveControl = null;
ActiveControl = Old;
// ActiveControl.FindForm().ResumeLayout();
// ActiveControl.ResumeLayout();
That seems to fire Leave, Validating and so on Events, no matter number of Form Controls and TabStopped Controls. You MAY need to SuspendLayout on either ActiveControl, or Form. My Control (Parent Panel) changes color when Active/Inactive, if I do not Suspend Layout on Form, parent panel gets an unwanted "flicker" effect.
Looking at the solution, it is very obvious, now I've found it, but took me half a day to try different things that solved one or another problem, but not all.
I know this a VERY old thread, but one of very few articles I've found on the subject of Forcing Leave Event to be Fired.

Categories

Resources