【问题标题】:Updating UI from NFC-Tag-Reader event handler is very slow从 NFC-Tag-Reader 事件处理程序更新 UI 非常慢
【发布时间】:2019-01-19 16:27:53
【问题描述】:

我有一个 ACR122U NFC 阅读器,我可以在其中读取 MiFare UltraLight NFC 标签。我为我的读者下载了一个框架。但是当调用事件处理函数时,GUI的更新很慢。

我在线程编程和事件处理方面没有太多经验。也许我的问题的解决方案很容易。

但是,它仅在 UpdateInterface() 方法中“逐个标签”更新,并且一次更新一个。我可以看到每个标签都消失了。所以UI的更新很慢。

我猜这与后台读取器类调用的(硬件)事件有关。

程序一般都在运行,只是速度很慢。

private void StartMonitor()
{
        //Function called when starting the Windows Forms Application
        IMonitorFactory monitorfactory = MonitorFactory.Instance;
        monitor = monitorfactory.Create(SCardScope.System);
        monitor.Start(ReaderNames[0]);
        monitor.StatusChanged += Monitor_StatusChanged;
}

private void Monitor_StatusChanged(object sender, StatusChangeEventArgs e)
{
        strPassportNo = "";
        strPassportNo = lPassportNumberNo.Text;

        if (e.NewState.ToString().ToLower().Contains("empty".ToLower()) == true)
        {
            //Interface should be deleted all by once now as no NFC tag is on the reader.
            UpdateInterface();
        }
}

private void UpdateInterface()
{
        if (InvokeRequired)
        {
            this.BeginInvoke(new Action(() =>
            {
                lPassportNumberNo.Text = "";
                lPassengerName.Text = "";
                lPax.Text = "";
                lTableNo.Text = "";
                lRoomNo.Text = "";
                pbTables.Hide();
                pbPasspic.Hide();
                this.BackgroundImage = BackgroundWelcome;
            }));
        }
        else
        {
            lPassportNumberNo.Text = "";
            lPassengerName.Text = "";
            lPax.Text = "";
            lTableNo.Text = "";
            lRoomNo.Text = "";
            pbTables.Hide();
            pbPasspic.Hide();
            this.BackgroundImage = BackgroundWelcome;
        }
}

预期的输出应该是 UI 的性能比实际快很多。或者至少其中包含数据的标签应该立即出现和消失。

【问题讨论】:

  • 听起来您想批量处理来自 monitor.StatusChanged 事件的 NFC 更新。不过,我看不到您在哪里更新 UI。您需要使用 beginupdate 方法在 UI 线程上进行这些更新。

标签: c# winforms nfc


【解决方案1】:

不确定这实际上是什么:this.BackgroundImage = BackgroundWelcome; 但真的有必要每次都分配这样的静态数据吗?

另外,我不认为您的更新事件的频率太高 - 屏幕上的信息应该是人类可读的,因此在读取整个标签后,它肯定只是对所有所需数据的一次更新。如果每个标签都有许多读取事件 - 则将它们全部存储到临时列表中并在读取端(整个标签)更新表单。 当我说“标签”时,我指的是整个 mifare 卡内容。

【讨论】:

    【解决方案2】:

    在我的情况下,UI 更新只是清除标签(请参阅 UpdateInterface())。但是我发现了“错误”。这是我在每次刷新时加载的“.jpg”文件和 BackgroundImage。虽然它“只是”1280x1024,但对于前端来说更新太多了。

    当我清除图像时,立即刷新。

    我现在的解决办法是:

    this.BackgroundImage = ((System.Drawing.Image(resources.GetObject("$this.BackgroundImage")));
    this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom;
    this.SetStyle(System.Windows.Forms.ControlStyles.OptimizedDoubleBuffer | System.Windows.Forms.ControlStyles.AllPaintingInWmPaint, true);
    

    在 Form1.Designer.cs 中

    以及使用以下类暂停和恢复布局(我在 Internet 的某个地方找到)

    public static class ControlHelper
    {
        #region Redraw Suspend/Resume
        [DllImport("user32.dll", EntryPoint = "SendMessageA", ExactSpelling = true, CharSet = CharSet.Ansi, SetLastError = true)]
        private static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam);
        private const int WM_SETREDRAW = 0xB;
    
        public static void SuspendDrawing(this Control target)
        {
            SendMessage(target.Handle, WM_SETREDRAW, 0, 0);
        }
    
        public static void ResumeDrawing(this Control target) { ResumeDrawing(target, true); }
        public static void ResumeDrawing(this Control target, bool redraw)
        {
            SendMessage(target.Handle, WM_SETREDRAW, 1, 0);
    
            if (redraw)
            {
                target.Refresh();
            }
        }
        #endregion
    }
    

    我还将“.jpg”文件更改为“.bmp”文件。现在界面流畅快速。

    还有@Jesting:

    不确定这实际上是什么:this.BackgroundImage = BackgroundWelcome;但是真的有必要每次都分配这样的静态数据吗?

    不,我本可以找到更好的解决方案。然而,由于应用程序非常小,而且我只有四个背景图像,我发现“硬编码”它更容易。

    最后,标签(-reader)并不是真正的问题。

    为了更新 UI,我使用了这个非常简单的函数:

    private void UpdateInterface(PassportDatabaseReader.Passport _passport)
        {
            if (InvokeRequired)
            {
                this.BeginInvoke(new Action<PassportDatabaseReader.Passport>(UpdateInterface), new object[] { _passport });
                return;
            }
            else
            {
                ControlHelper.SuspendDrawing(this);
                new Thread(() => ChangeBackground(BackgroundPassport)).Start();
                lPassportNumberNo.Text = _passport.PassportNo;
                strPassportNo = _passport.PassportNo;
                lPassengerName.Text = _passport.Name.Replace('$','\n');
                lPax.Text = _passport.Pax;
                lTableNo.Text = _passport.TableNo;
                lRoomNo.Text = _passport.RoomNo;
                pbTables.Hide();
                try
                {
                    pbPasspic.Load("..\\..\\Pics\\" + _passport.PassportNo + ".png");
                    pbPasspic.Show();
                    pbTables.ImageLocation = "..\\..\\Tischordnung_" + _passport.TableNo + ".png";
                    pbTables.Show();
                }
                catch (Exception)
                {
                    throw;
                }
                ControlHelper.ResumeDrawing(this);
            }
        }
    

    该应用程序是一个“婚礼护照”阅读器,可在屏幕上显示姓名、客人房间号、桌号以及“护照”图片。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-02
      • 2015-08-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多