0

1 秒に 1 回タイマーをインクリメントし、ラベルのテキストを更新する WinForms アプリがあります。2 番目のタイマーは 20 ミリ秒ごとに 1 回インクリメントして、最近のマウスの動きを探し、現在の座標を別のラベルに書き込みます。

プログラムが Alt+F4 を受け取ると、「MessageBoxQueryClose」をインスタンス化し、ユーザーが操作を閉じるか再開するよう求められます。MessageBox が表示される前に、1 秒ごとのタイマーの起動を停止し、ユーザーが「続行してください」と言った後に再び有効にしたいと思います。

ここで、いくつかの「奇妙な」動作を観察しました。MessageBox が開いていて、マウスが移動しているときに、1 秒ごとのタイマーが再び起動します。

フォームのコード:

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();
        }
    }
}

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;
            }
        }
    }
}

私の問題はタイマーとスレッドに関するものであるという直感がありますが、最近 .Net を使い始めたばかりなので、洞察をいただければ幸いです。

br、クリス

4

2 に答える 2

3

イベントがCompareCursorPosition timer1_Tick() を呼び出し、これが Display_ResetFallback() を呼び出し、timer2再び開始します。

したがってtimer2、QueryClose() で停止しますが、その後timer1_Tickイベントが発生し、timer2再び開始します。

Display_ResetFallback() を変更して、現在実行中の場合にのみタイマーが再起動されるようにすることができます。

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

補足として、私はおそらく MessageBoxQueryClose クラスを完全に取り除き、FormClosingそれに応じてイベントを変更するだけです:

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

    if (MessageBox.Show("Close program ?", "timers", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) == DialogResult.No)
    {
        e.Cancel = true;
        timer2.Start();
    }
}
于 2013-06-15T13:27:01.680 に答える