1

我在 Windows CE 5.0 上运行的 .NET CF 2.0 应用程序中遇到了一些奇怪的行为。

我有一个定期更新控件的计时器,该控件还可以接收来自用户的点击并按住手势(在鼠标按下处理程序中)。我发现,当 TAH 开始(但在它退出之前)时,一个计时器事件可以开始处理,该事件在执行中途抢占鼠标按下处理程序。

据我的研究告诉我,这不是正常行为,我只是误解了计时器/事件吗?难道仅仅是 SHRecognizeGesture 正在调用 Application.DoEvents 的等价物吗?

无论如何,有没有人有一个“好”的方法来修复这个例子,这样当应用程序检查 TAH 时,计时器委托不会“滴答”。

请参阅下面的示例程序来说明此问题(点击并按住列表框下方的空白区域以生成日志消息)。

提前致谢。

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace DeviceApplication1
{
    public class BugExample : Control
    {
        [Flags]
        internal enum SHRGFLags
        {
            SHRG_RETURNCMD = 0x00000001,
            SHRG_NOTIFYPARENT = 0x00000002,
            SHRG_LONGDELAY = 0x00000008,
            SHRG_NOANIMATION = 0x00000010,
        }

        [DllImport("aygshell.dll")]
        private extern static int SHRecognizeGesture(ref SHRGINFO shrg);

        private struct SHRGINFO
        {
            public int cbSize;
            public IntPtr hwndClient;
            public int ptDownx;
            public int ptDowny;
            public int dwFlags;
        }

        public bool TapAndHold(int x, int y)
        {
            SHRGINFO shrgi;

            shrgi.cbSize = 20;
            shrgi.hwndClient = this.Handle;
            shrgi.dwFlags = (int)(SHRGFLags.SHRG_RETURNCMD );
            shrgi.ptDownx = x;
            shrgi.ptDowny = y;

            return (SHRecognizeGesture(ref shrgi) > 0);

        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);

            BugExampleForm parent = (BugExampleForm)this.Parent;

            //The problem is that the parent tick event will fire whilst TapAndHold is running
            //Does TapAndHold perform an equivelant to Application.DoEvents?
            parent.AddLog("Tap Hold - Enter");
            parent.AddLog(String.Format("Tap Hold - Exit - {0}", TapAndHold(e.X, e.Y)));

        }
    }

    public class BugExampleForm : Form
    {
        Timer _timer;
        BugExample _example;
        ListBox _logBox;

        public BugExampleForm()
        {
            _example = new BugExample();
            _example.Dock = DockStyle.Fill;

            _logBox = new ListBox();
            _logBox.Dock = DockStyle.Top;

            _timer = new Timer();
            _timer.Interval = 1000;
            _timer.Enabled = true;
            _timer.Tick += new EventHandler(_timer_Tick);

            this.SuspendLayout();
            this.Text = "Example";
            this.Size = new System.Drawing.Size(200, 300);

            this.Controls.Add(_example);
            this.Controls.Add(_logBox);
            this.ResumeLayout();
        }

        void _timer_Tick(object sender, EventArgs e)
        {
            AddLog("Tick");
        }

        public void AddLog(string s)
        {
            _logBox.Items.Add(s);
            _logBox.SelectedIndex = _logBox.Items.Count - 1;
        }
    }
}

我无法内联链接图像,所以这里是一个截图的链接,说明了这种行为

编辑:在我的实际应用程序中,计时器滴答正在更新控件。所以我仅限于在一个线程中工作。(我也无法通过事件处理程序真正完成我所需要的)。

4

4 回答 4

0

解决此问题的方法可能是在公共静态类变量(可能是单例样式)中设置布尔标志。例如,将其称为 IgnoreTick。

在鼠标按下处理程序中将 IgnoreTick 设置为 true。在您的刻度处理程序中检查 IgnoreTick 的值。如果是真的,返回,如果不是,做你所做的。您当然必须添加一个鼠标向上处理程序,在该处理程序中将 IgnoreTick 设置回 false。

于 2009-10-29T02:38:01.643 回答
0

为什么不在处理程序开始时将 Timer 的 Enabled 属性设置为 false 并在结束时设置回 ture?

于 2009-10-29T03:15:16.880 回答
0

由于 Timer 是一个 WinForms 计时器,它与 UI 和所有 UI 处理程序(包括您的鼠标按下处理程序)在相同的线程上下文中运行。这意味着在给定时间只能运行一个。您看到的问题是因为您的鼠标处理程序正在执行您正在交换执行的其他任务。

您可以使用关键部分(监视器)防止这种情况发生。您可以在整个 mousedown 处理程序周围加一个锁(或在开始时监视输入并在结束时监视退出),然后在锁定同一对象的计时器进程中加一个锁。这意味着整个 mousedown 处理程序必须在计时器 proc 可以运行之前执行,并且计时器“滴答”实际上会排队(除非您使用 Monitor.TryEnter 来专门避免这种情况)。

可能的缺点是反过来也是如此 - 在任何挂起的计时器过程完全完成之前,您的 mousedown 处理程序永远不会运行。这是否是一个问题将取决于您的用例,并且您始终可以在计时器过程中通过查找事件或标志以提前退出来缓解它。

于 2009-10-29T13:07:02.837 回答
0

然而,可能会阻止这种行为的另一个答案(请参阅我的其他答案以了解您为什么看到它的解释)将从使用 Forms 计时器更改为 Threading 计时器,因此线程 proc 位于单独的线程上。如果 timer proc 不影响 UI,这应该可以正常工作。如果您仍然看到争用(我们不知道您的计时器 proc 到底在做什么),将计时器 proc 开始时的线程优先级更改为像“BelowNormal”这样的东西将防止从 UI 中占用 CPU 量。

于 2009-10-29T13:09:40.380 回答