MouseLeave eventhandler is too slow - c#

I'm using the MouseLeave event to check if the user left my form and to close my window, but using
this.MouseLeave += new System.EventHandler(this.InvisibleForm_Leave);
is too slow, only if I'm going to leave my form slowly the event is fired, moving it in a normal way / a little bit faster I don't get a leave event.
Therefore I tried to check on my own if the mouse left my form or not:
private void checkPos()
{
Rectangle rec = this.Bounds;
while (true)
{
Point point = new Point(Cursor.Position.X, Cursor.Position.Y);
if (!rec.Contains(point))
{
Console.WriteLine("leaving");
this.Close();
}
Thread.Sleep(100);
}
}
started in a own thread after creating the form:
public MyForm()
{
InitializeComponent();
Thread m_mouseListenerThread = new Thread(new ThreadStart(this.checkPos));
m_mouseListenerThread.Start();
}
But with this I have more or less the same problem, leaving the area still returns true after checking it with rec.Contains(point) only after a second he is going to execute the if code, but sometimes he's getting it in an instant.
The second problem with this is that I'm getting a thread exception in the this.Close(); line in the checkPost() method:
Cross-thread operation not valid: Control 'MyForm' accessed from a thread other than the thread it was created on.
Now I don't really know how to implement the mouse leaving part in another way.

I don't think MouseLeave performance is the issue here. I've used the MouseLeave (in combination with MouseEnter and MouseMove) to automatically fade in/out forms. It works :).
Here's a sample form with just a Label:
If MouseLeave is handled for both the Label and the Form, the event handler always fires regardless of how fast I move the mouse. For example:
this.label1.MouseLeave += new System.EventHandler(this.HandleMouseLeave);
this.MouseLeave += new System.EventHandler(this.HandleMouseLeave);
private void HandleMouseLeave(object sender, EventArgs e)
{
Debug.WriteLine(string.Format("MouseLeave: {0}", DateTime.Now));
}
However, if I remove the MouseLeave handler for label1, I am able to reproduce the behavior that you are seeing. If I move the mouse slowly from label1 (orange) to the form (green) and outside, the event fires. If I move the mouse quickly from label1 to outside of the form, the event does not fire.
So, what I think is happening is that a child control of your form is firing a MouseLeave event, and you are not handling that event. The reason you see the event fire when you move the mouse slowly is because you are hovering over the form area long enough to produce the event.
Further, spawning a separate thread to monitor MouseLeave events is not a good approach. Your performance will suffer as this thread polls for an event state (as opposed to waiting for an event), you are creating an unnecessary headache of starting/stopping the threads, and you will need to invoke back onto the UI thread whenever you want to do anything with the form (as you have learned). If you have the time to revisit the MouseLeave event approach, I would highly recommend that you do so. Good luck!

For the mouse leaving part, I am not quite sure. Maybe you can try to handle that by MouseMove event?
For the invalid cross-thread operation issue, you simply cannot access a control which is owned by another thread (it's the UI thread in your case). Use Control.BeginInvoke or Control.Invoke instead.

I faced same problem, do that:
put timer in form.
Put your code in timer tick event like mouse leave:
Label1.BackColor=Color.PaleGreen;
Set timer interval to less than 30
Use this function
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
timer1_Tick(label1(example), e);
}
Put this in formload event
timer1.Tick += timer1_Tick;
the code will run very quickly and easy , you will never see any problem like this again

Related

C# Winform panel Shown event

Is there an event for panel that is equivalent to form event Shown?
I had a few couple of panel switching within a form which will never be closed.
However i couldn't find anything close to an event like Shown which is used in form.
The closes i had is Paint event. However i only wish to update the panel once every time it is shown.
Form.Shown is not raised every time the form is shown, rather it Occurs whenever the form is first displayed. This being said, there is no Panel.Shown event, and no event which is raised "whenever a panel is first displayed".
You can simulate this behavior with the Panel.Paint event, using a flag to keep track of whether it's been "shown" once before. This will make it behave similar to Form.Shown.
private bool panel1Painted = false;
private void panel1_Paint(object sender, PaintEventArgs e)
{
if (!panel1Painted)
{
// do your shown stuff here
panel1Painted = true;
}
}
To keep in the spirit of Form.Shown, you may want to reset the flag if the Panel is reconstructed. This is not the same as shown.
You could listen on the VisibleChanged event and only act on when visibility = true.
https://msdn.microsoft.com/en-us/library/system.windows.forms.panel_events%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396
You could also experiment with the Enter and Invalidated events to see if these give you the results you want.
Or if disabling the panel when leaving it is an option, you might be able to use the EnabledChanged event in your toolbox.

PreviewMouseLeftButtonUp event doesn't get called when mouse clicked

I have a listview in which I display objects with their state and name. The state is surrounded by a button and when I click on it the state changes from active to inactive or the other way round.
Now I want to change the state when I click the mouse button down and change it back when the mouse button goes up. My button has to event "PreviewMouseLeftButtonDown" and "PreviewMouseLeftButtonUp" as you can see in the code below. In the SendStateMessage() method the state is send to a SCADA-Server and the server sends me the new state back and the GUI edits the change.
Normally it doesn't make any problems, but when I click to fast the "PreviewMouseLeftButtonUp" event doesn't get called. So the "MouseUp" is not shown at the consol.
I tried to call a Task.Delay() in the first mouseDown event because i thougt that the method needs some more time but this didn't work well. So i want to ask you if somebody has an idea what the problem could be and a way how this issue can be fixed.
Thanks for your time.
private void Button_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
//_CurrentItem is an object of the class VM on which the click is executed.
_CurrentItem = sender as FrameworkElement).DataContext as VM
_CurrentItem.SendStateMessage();
}
private void Button_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
Console.WriteLine("MouseUp");
}
EDIT:
After a bit of time passing by I had another idea to solve the problem, which is also working. I only wait for the MouseDownEvent and if this gets triggered i have a loop where i wait as long as the mouse is pressed, when the mouse is released i could leave the loop and there i inserte the code which i wanted to do in the MouseUPEvent.
You can also wait for the MouseDownEvent and if this gets triggered make a loop where you wait as long as the mouse is pressed, when the mouse is released you could leave the loop and inserte there your code which you wanted to do in the MouseUpEvent.
In my case another control consumed the mouseup event. So I catch the mouseup event on level of the top most windows.

XNA Game does not update while "dragging" window, any event handlers?

I'm new with XNA and C#, and I've come to the point in my XNA project where I need event handlers to predict when the game loses focus so that I can sync music and visuals once it gains focus again. But I got one problem; the game does not "update" while being dragged, but I can't seem to find an suitable event listener for this. I've tried:
System.Windows.Forms.Control.FromHandle(Window.Handle).Move += new EventHandler(DeactivateGame);
This one calls "DeactivateGame" tons of times while moving the window. But even if it works, despite the fact it calls the function more than once, I can't see a event handler that calls a function when the window handle is released so that the game can resume again by calling "ActivateGame"
A sidenote (if it helps);
this.Activated += new EventHandler<EventArgs>(NotifyActivated);
this.Deactivated += new EventHandler<EventArgs>(NotifyDeactivated);
These event handlers works fine when minimizing the window or putting focus on something else than the game window, but it does not register the window being dragged. Maybe obvious for the one used to programming, but I just want to make sure I've given enough information
EDIT:
The function I want to add as the result of the event handler is a DateTime/TimeSpan that gets called when the window is out of focus or dragged. When dropped or gets focus again, this will compare the current time with the time set when the window lost focus to calculate the lost time in between.
For detecting when the XNA window is being dragged, you were on the right track using the Window.Handle with Windows Forms. You can simply listen to the ResizeBegin and ResizeEnd events to know when the user starts moving the window and when they release it.
var xnaWinForm = (System.Windows.Forms.Control.FromHandle(Window.Handle) as System.Windows.Forms.Form);
if (xnaWinForm != null)
{
xnaWinForm.ResizeBegin += new EventHandler(xnaWinForm_ResizeBegin);
xnaWinForm.ResizeEnd += new EventHandler(xnaWinForm_ResizeEnd);
}
And here's what the event handlers look like.
void xnaWinForm_ResizeBegin(object sender, EventArgs e)
{
// XNA window is starting to be moved.
}
void xnaWinForm_ResizeEnd(object sender, EventArgs e)
{
// XNA window was released and is no longer being moved.
}
Then just combine this with the other events you mentioned for determining when the window is minimized/restored/active to determine how long the window has been "inactive" for.

How would I stop a thread, allow a UI event to be handled, and then "restart" the thread?

I have a form that appears as shown in the attached image. I have two parts of the form that concern this question: the TabControl, and the Panel, as shown in the image. It should be noted that the panel is NOT within the TabControl.
My situation is that I have a thread that executes continuously when the button, displayed in melt-your-eyes green in the Panel, is clicked. The thread polls the device which I'm interfacing with and updates the controls in the "Status" GroupBox at the bottom of the TabControl. When the user clicks on a control in the TabControl (tabControl_Enter event), I trigger a ManualResetEvent which lets the thread finish its iteration so that I can perform the IO required by the clicked control. The code to to suspend the thread is as follows:
private void StopSynchThread()
{
synchWaitHandle.Reset();
//various UI changes
}
private void updateSynchStat()
{
while (true)
{
synchWaitHandle.WaitOne();
try
{
updateSynch();
}
}
What I would like to do is then restart the thread automatically, instead of by button press, as is currently done. What I'm trying to do is avoid having to restart the thread by conditionally calling StartSynchThread() within each of the "bazillion" UI event handlers. StartSynchThread() is defined as:
private void StartSynchThread()
{
synchWaitHandle.Set();
}
Is there a precedent or decent paradigm for handling this? Without any concept of how to do so, I was thinking that I could alter my function that performs the IO with the device to generate an event after it gets a response from the device, but that seems inelegant.
Any ideas? I appreciate your insights. Thanks.
If you really can fire it off with a simple button click, you ought to be able to just put a timer on the form that will periodically check for the right conditions and then "push" the button (call synchWaitHandle.Set();) automatically.

C# Form Move Stopped Event

Is there any event in C# that fires when the form STOPS being moved. Not while its moving.
If there is no event for it, is there a way of doing it with WndProc?
The ResizeEnd event fires after a move ends. Perhaps you could use that.
This is not a failsafe solution, but it's pure .NET and it's dead simple. Add a timer to your form, set it to a relatively short delay (100-150 ms seemed OK for me). Add the following code for the Form.LocationChanged and Timer.Tick events:
private void Form_LocationChanged(object sender, EventArgs e)
{
if (this.Text != "Moving")
{
this.Text = "Moving";
}
tmrStoppedMoving.Start();
}
private void Timer_Tick(object sender, EventArgs e)
{
tmrStoppedMoving.Start();
this.Text = "Stopped";
}
If you want more exact handling (knowing exactly when the mouse button is release in the title bar and such) you will probably need to dive into monitoring windows messages.
I had the same problem with a user control, but it does not have the ResizeEnd event. The solution, which worked is to override the WndProc method and listen for EXITSIZEMOVE.
See example here
Just set a flag to true when onmove events are fired. If a mouseup event happens and the flag is true, the form stopped being moved.
I admit this probably won't work in the case of a user moving a form via the keyboard, but that's pretty rare.
I tested ResizeChanged event, and it works fine, however I don't know relation between move and resize, but it works for me

Categories