0

现在我很欣赏这个故事的寓意是“不要占用 UI 线程”,但我们试图通过尽可能长时间保持 UI 线程上的东西来亲吻,但我认为我们刚刚达到了临界点,我们正在将不得不改变我们的设计。

但无论如何......我在我们的设备上注意到的一些在桌面上不会发生的事情:当你占用 UI 线程时,它会丢弃键。这是一个显示问题的非常简单的应用程序。

using System;
using System.Windows.Forms;

namespace DeviceApplication14
{
    public partial class Form1 : Form
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [MTAThread]
        static void Main()
        {
            Application.Run(new Form1());
        }

        private int ctr;

        public Form1()
        {
            InitializeComponent();
            KeyPreview = true;
            KeyDown += Form1_KeyDown;
        }

        void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            for (int i = 0; i < 1000000; i++)
            {

            }
            ctr++;
            button1.Text = ctr.ToString();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            ctr = 0;
            button1.Text = ctr.ToString();
        }

        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.button1 = new System.Windows.Forms.Button();
            this.button2 = new System.Windows.Forms.Button();
            this.SuspendLayout();
            // 
            // button1
            // 
            this.button1.Location = new System.Drawing.Point(235, 137);
            this.button1.Name = "button1";
            this.button1.Size = new System.Drawing.Size(329, 239);
            this.button1.TabIndex = 0;
            this.button1.Text = "button1";
            // 
            // button2
            // 
            this.button2.Location = new System.Drawing.Point(62, 291);
            this.button2.Name = "button2";
            this.button2.Size = new System.Drawing.Size(72, 20);
            this.button2.TabIndex = 1;
            this.button2.Text = "Clear";
            this.button2.Click += new System.EventHandler(this.button2_Click);
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
            this.AutoScroll = true;
            this.ClientSize = new System.Drawing.Size(638, 455);
            this.Controls.Add(this.button2);
            this.Controls.Add(this.button1);
            this.Name = "Form1";
            this.Text = "Form1";
            this.ResumeLayout(false);

        }

        #endregion

        private Button button1;
        private Button button2;
    }
}

当我在我的自定义框上运行它时,我可以连续按四个键,但我的 ctr 只增加 2。如果我然后添加几个零(以补偿桌面更快的速度)并在桌面上运行它,我会得到所有的键。

这里发生了什么?

4

3 回答 3

2
for (int i = 0; i < 1000000; i++)
            {

            }

提供时间延迟的空循环表明对事件驱动模型的理解不足。

Windows CE 的事件处理程序与桌面版本的 Windows 完全不同,虽然 Windows 可以容忍这种类型的滥用,但 Windows CE 不会。

如果您在诸如此类的空循环中吸收大量处理时间,而不是调用延迟例程将控制权正确释放回调度程序,则不会调用事件处理程序。如果没有足够频繁地调用事件处理程序,那么您将丢失事件。有各种缓冲区可以存储其中一些事件,但根据输入设备(键盘、触摸屏等)的不同,这些缓冲区可能不足或不存在。

这里的关键是便携式设备上的事件处理程序没有大缓冲区。台式计算机具有大量用于键盘和鼠标操作的缓冲区。

还有许多其他差异,但最重要的是,您确实需要正确释放线程并正确延迟,而不是这些简单的空循环延迟。

Windows CE 计时器在这里更合适 - 使用 keydown 例程启动计时器,并在它触发时执行所需的操作。这会将控制权释放回 UI,以便其他事件可以运行。

另外,请记住,虽然 Windows CE 是多线程/多任务处理,但最好将您的程序视为一次只运行一件事。操作系统和事件模型可能正在发送您的应用程序事件(而不是缓冲它们)并且您的应用程序处于此延迟例程中而忽略它们。在执行该循环时,您不会看到其他事件(包括按键)。根据系统的负载和性能,延迟可能会运行几毫秒到数百毫秒——你不能指望它每次运行时都运行相同的时间长度——这是使用实时计时器的另一个原因。

-亚当

于 2009-01-16T18:49:16.523 回答
1

一旦消息进入队列,Windows CE 将不会“丢弃”任何键。我的猜测是你使用了太多的量子,键盘驱动程序本身并没有得到所有的键,因此不能传递它们。您可以通过调用PostKeybdMessage而不是使用键盘本身来排除硬件或驱动程序交互来验证这一点。

于 2009-01-16T18:46:26.500 回答
1

这个问题与 BSP 中的一个错误(显然来自一些飞思卡尔代码)有关,这意味着键盘驱动程序以比预期低得多的优先级中断运行。

现在已修复,一切正常。:)

于 2009-10-28T15:52:19.080 回答