为什么我的事件“ myTimer_Elapsed无法更新设备上的标签?”

时间:2019-06-12 03:15:18

标签: c# xamarin.forms cross-platform visual-studio-2019 system.timers.timer

很抱歉,如果有人提出这个要求。我找不到这个问题的具体答案,被困住了。我正在学习定时器。我是VBA程序员,并且涉足C#。

我正在尝试编写一个跨平台的应用程序,但是myTimer.Elapsed事件遇到了无法正常执行的更新标签的问题。

我已阅读Goalkicker.com的C#专业版注释中的计时器一章,并尝试复制其倒数计时器。我也阅读了Timer.Elapsed事件的Microsoft API。都没有给我关于我要去哪里错误的明确答案。 Google也不太友善,因为我可能查询不正确。

我试图停止计时器,只是允许该方法运行,直接在我的Elapsed方法中写入标签,并在一个单独的方法中更新标签(如代码所示)。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//using System.Threading;
using System.Timers;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Essentials;
using Plugin.Geolocator;

namespace LocationServices
{
    public partial class MainPage : ContentPage
    {
        public int timeLeft = 3;
        public Timer myTimer = new Timer();

        SensorSpeed speed = SensorSpeed.UI; //ignore

        public MainPage()
        {
            InitializeComponent();
            cmdGetLocation.Clicked += GetLocation; //ignore
            cmdStartTimer.Clicked += StartTimer;
            Accelerometer.ReadingChanged += MainPage_ReadingChanged; //ignore

            InitializeTimer();
        }

        private void UpdateTimeLeftLabel(string NumberToDisplay)
        {
            txtTimeRemaining.Text = "Time left: " + NumberToDisplay;
        }

        private void InitializeTimer()
        {
            myTimer.Interval = 1000;
            myTimer.Enabled = true;
            myTimer.Elapsed += MyTimer_Elapsed;
            UpdateTimeLeftLabel(timeLeft.ToString()); //working just fine
        }

        private void MyTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            myTimer.Stop();
            UpdateTimeLeftLabel(timeLeft.ToString()); //this one is not working.

            if (timeLeft <= 0)
            {
                myTimer.Dispose();
            }
            else
            {
                timeLeft -= 1;
                myTimer.Start();
            }
        }

        private void StartTimer(object sender, EventArgs e)
        {
            myTimer.Start();
        }
    }
}

我的计时器事件正在触发,因为按预期达到了断点。正如在即时窗口中已验证的那样,正在调整timeLeft变量。只是标签没有更新。

2 个答案:

答案 0 :(得分:1)

使用BeginInvokeOnMainThread强制您的UI代码在UI线程上运行

private void UpdateTimeLeftLabel(string NumberToDisplay)
    {
        Device.BeginInvokeOnMainThread( () => {
          txtTimeRemaining.Text = "Time left: " + NumberToDisplay;
        });
    }

答案 1 :(得分:0)

只需在此处添加更多信息作为支持信息

.NET包含四个名为Timer的类,每个类提供不同的功能:

  • System.Timers.Timer,它会定期触发一个事件并在一个或多个事件接收器中执行代码。该类旨在在多线程环境中用作基于服务器的组件或服务组件。它没有用户界面,并且在运行时不可见。
  • System.Threading.Timer,它定期在线程池线程上执行一个回调方法。回调方法是在实例化计时器且无法更改时定义的。与System.Timers.Timer类类似,该类旨在用作多线程环境中的基于服务器或服务的组件。它没有用户界面,并且在运行时不可见。
  • System.Windows.Forms.Timer(仅.NET Framework),这是一个Windows Forms组件,它会定期触发一个事件并在一个或多个事件接收器中执行代码。该组件没有用户界面,并且设计用于单线程环境。它在UI线程上执行。
  • System.Web.UI.Timer(仅.NET Framework),一个ASP.NET组件,该组件定期执行异步或同步网页回发。

现在,您的问题是您最有可能使用线程计时器。这意味着您需要Marshall返回到 UI线程,因为您无法从另一个线程更新 UI

请参阅杰森斯的答案