0
votes

I have a WinForms app that increments a timer once per second and updates a labels' text. A second timer increments once every 20msec to look for recent mouse movements and writes the current coordinates to another label.

When the program receives Alt+F4 I instantiate "MessageBoxQueryClose" where the user is asked to close or resume operation. Before the MessageBox is displayed I'd like to stop the once-per-second timer from firing, and after the user said "please continue" to re-enable it.

This is where I observed some 'strange' behavior: the once-per-second timer fires again while the MessageBox is open and the mouse is moved.

Code for the form:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Globalization;


namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private bool _altF4Pressed = false;

        private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Alt && e.KeyCode == Keys.F4)
                _altF4Pressed = true;
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            // show the MessageBox asking the user if the programm should really exit
            MessageBoxQueryClose msgBoxQC = new MessageBoxQueryClose();
            msgBoxQC.QueryClose(ref _altF4Pressed, ref timer2, ref e);
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            timer1.Interval = 20;
            timer1.Enabled = true;

            timer2.Interval = 1000;
            timer2.Enabled = true;
        }


        bool toggle = false;

        private void timer2_Tick(object sender, EventArgs e)
        {
            if (toggle)
                label1.Text = "tick";
            else
                label1.Text = "tack";

            toggle = !toggle;
        }


        Point oldPos, newPos;

        private void timer1_Tick(object sender, EventArgs e)
        {
            newPos = Cursor.Position;
            label2.Text = Convert.ToString(newPos.X + ", " + newPos.Y);

            CompareCursorPosition();

            oldPos = newPos; 
        }

        private void CompareCursorPosition()
        {
            if (oldPos != newPos)
                Display_ResetFallback();
        }

        private void Display_ResetFallback()
        {
            timer2.Stop();
            timer2.Start();
        }
    }
}

Code for MessageBoxQueryClose:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;


namespace WindowsFormsApplication1
{
    class MessageBoxQueryClose
    {
        public void QueryClose(ref bool _altF4Pressed, ref Timer timer, ref FormClosingEventArgs e) 
        {
            if (_altF4Pressed)
            {
                // first, disable timer2 to stop Form1.label1 from being updated 
                timer.Enabled = false;

                if (e.CloseReason == CloseReason.UserClosing)
                {
                    DialogResult res;

                    res = MessageBox.Show("Close program ?", "timers",
                                MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation);


                    if (res == DialogResult.Yes)
                    {
                        return;
                    }

                    // if program execution shall continue, re-enable timer2
                    timer.Enabled = true;
                }
                e.Cancel = true;
                _altF4Pressed = false;
            }
        }
    }
}

I have the gut feeling that my issue is about timers and threading, but I only recently started out with .Net, so any insight is appreciated.

br, Chris

2
about the mouse move,in the control where you are checking for mousemove you should subscribe to that controls event for mouse move and there set the label text for mouse coordinates with e.X and e.Y - terrybozzio

2 Answers

3
votes

Your timer1_Tick event calls CompareCursorPosition(), which calls Display_ResetFallback(), which starts timer2 again.

So you stop timer2 in QueryClose(), but then the timer1_Tick event fires, starting timer2 up again.

You could modify Display_ResetFallback() to make sure your timer is only restarted if it's currently running:

if (timer2.Enabled)
{
    timer2.Stop();
    timer2.Start();
}

As a side note, I'd probably get rid of the MessageBoxQueryClose class entirely and just modify your FormClosing event accordingly:

if (e.CloseReason == CloseReason.UserClosing)
{
    timer2.Stop();

    if (MessageBox.Show("Close program ?", "timers", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) == DialogResult.No)
    {
        e.Cancel = true;
        timer2.Start();
    }
}
0
votes

You can try this...

        timer1.Stop();
        label1.Text = timer1.Enabled == false ?"timer disabled":"timer enabled";
        if (MessageBox.Show("Close program ?", "timers",
              MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) == DialogResult.OK)
        {
            //do stuff here if you want
        }
        timer1.Start();
        label1.Text = timer1.Enabled == false ? "timer disabled" : "timer enabled";

just put those label text for you to check. this edit you dont require the class

EDIT:

public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private bool _altF4Pressed = false;

        private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Alt && e.KeyCode == Keys.F4)
                _altF4Pressed = true;
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            //show the MessageBox asking the user if the programm should really exit
            //MessageBoxQueryClose msgBoxQC = new MessageBoxQueryClose();
            //msgBoxQC.QueryClose(ref _altF4Pressed, ref timer2, ref e);

            if (_altF4Pressed)
            {
                this.timer2.Stop();
                if (MessageBox.Show("Close program ?", "timers",
                                MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) == DialogResult.No)
                {
                    e.Cancel = true;
                    this.timer2.Start();
                }

            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            timer1.Interval = 20;
            timer1.Enabled = true;

            timer2.Interval = 1000;
            timer2.Enabled = true;
        }


        bool toggle = false;

        private void timer2_Tick(object sender, EventArgs e)
        {
            if (toggle)
                label1.Text = "tick";
            else
                label1.Text = "tack";

            toggle = !toggle;
        }


        //Point oldPos, newPos;

        private void timer1_Tick(object sender, EventArgs e)
        {

            label2.Text = MousePosition.X.ToString() + " , " + MousePosition.Y.ToString();
        }

        //private void CompareCursorPosition()
        //{
        //    if (oldPos != newPos)
        //        Display_ResetFallback();
        //}

        //private void Display_ResetFallback()
        //{
        //    timer2.Stop();
        //    timer2.Start();
        //}
    }

Just put my first post inside your code....It stops for me,and no need for the extra class,removed the 2 points and the 2 methods(Display_ResetFallback and CompareCursorPosition),but you can use them(the 2 point variables) if you want and inside timer1 do your checks.