2

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.

hippietrail
  • 15,848
  • 18
  • 99
  • 158
dontcare
  • 935
  • 3
  • 16
  • 34

3 Answers3

3

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!

Steve Wong
  • 2,038
  • 16
  • 23
  • tried it, so long the i have a border its working fine, but when using this.FormBorderStyle = FormBorderStyle.None; for my form it have the same problems – dontcare Apr 23 '12 at 07:58
  • Can you post a small sample with the problem? I typically do this for fading popup borderless popup windows, and it works fine. I don't think the form border style should have any affect on the MouseLeave events. – Steve Wong Apr 23 '12 at 12:30
2
  1. For the mouse leaving part, I am not quite sure. Maybe you can try to handle that by MouseMove event?
  2. 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.
Hailei
  • 42,163
  • 6
  • 44
  • 69
  • 1. i think i got the problem, i'm changing the size from the form and when checking the rec he got the old bounds saved and not the new size bounds after the change 2. will try it – dontcare Apr 20 '12 at 11:51
0

I faced same problem, do that:

  1. put timer in form.
  2. Put your code in timer tick event like mouse leave:

    Label1.BackColor=Color.PaleGreen;
    
  3. Set timer interval to less than 30

  4. Use this function

    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        timer1_Tick(label1(example), e); 
    }
    
  5. 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

Lukas Körfer
  • 13,515
  • 7
  • 46
  • 62
  • 1
    Usually it is a bad idea to use timers for problems like those. You already have an event you can handle, so one should stick with it. – Lukas Körfer Jan 30 '17 at 09:46