为什么我的活动“myTimer_Elapsed 没有更新我设备上的标签?
Why isn't my event "myTimer_Elapsed updating the label on my device?
很抱歉有人问过这个问题。我找不到具体的这个问题的答案并且被卡住了。我现在正在学习定时器。我是一名 VBA 程序员并且涉猎 C#。
我现在正在尝试编写一个跨平台应用程序,但我的 myTimer.Elapsed 事件无法按预期更新标签。
我已经阅读了 goalkicker.com 的 C# 专业人士笔记中的计时器章节,并尝试复制他们的倒数计时器。我还阅读了 Microsoft API for Timer.Elapsed 事件。关于我哪里出错了,他们都没有给我一个明确的答案。 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 变量正在调整,已在即时 window 中得到验证。只是标签没有更新。
使用 BeginInvokeOnMainThread
强制您的 UI 代码在 UI 线程
上 运行
private void UpdateTimeLeftLabel(string NumberToDisplay)
{
Device.BeginInvokeOnMainThread( () => {
txtTimeRemaining.Text = "Time left: " + NumberToDisplay;
});
}
只是在这里添加更多信息作为支持信息
.NET 包括四个名为 Timer 的 classes,每个都提供不同的功能:
System.Timers.Timer
,它触发事件并定期在一个或多个事件接收器中执行代码。 class 旨在用作多线程环境中的 server-based 或服务组件;它没有用户界面,在运行时不可见。
System.Threading.Timer
,定时在线程池线程上执行单个回调方法。回调方法在定时器实例化时定义,不能更改。与 System.Timers.Timer class 一样,此 class 旨在用作多线程环境中的 server-based 或服务组件;它没有用户界面,在运行时不可见。
System.Windows.Forms.Timer
(仅限 .NET Framework),一种 Windows Forms 组件,它触发事件并定期在一个或多个事件接收器中执行代码。该组件没有用户界面,专为在 single-threaded 环境中使用而设计;它在 UI 线程上执行。
System.Web.UI.Timer
(仅限 .NET Framework),一个定期执行异步或同步网页回发的 ASP.NET 组件。
现在您的问题是您很可能正在使用线程计时器。这意味着您需要编组回到 UI 线程 ,因为您无法更新来自 UI 的日期另一个线程。
查看 Jason 的回答
很抱歉有人问过这个问题。我找不到具体的这个问题的答案并且被卡住了。我现在正在学习定时器。我是一名 VBA 程序员并且涉猎 C#。
我现在正在尝试编写一个跨平台应用程序,但我的 myTimer.Elapsed 事件无法按预期更新标签。
我已经阅读了 goalkicker.com 的 C# 专业人士笔记中的计时器章节,并尝试复制他们的倒数计时器。我还阅读了 Microsoft API for Timer.Elapsed 事件。关于我哪里出错了,他们都没有给我一个明确的答案。 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 变量正在调整,已在即时 window 中得到验证。只是标签没有更新。
使用 BeginInvokeOnMainThread
强制您的 UI 代码在 UI 线程
private void UpdateTimeLeftLabel(string NumberToDisplay)
{
Device.BeginInvokeOnMainThread( () => {
txtTimeRemaining.Text = "Time left: " + NumberToDisplay;
});
}
只是在这里添加更多信息作为支持信息
.NET 包括四个名为 Timer 的 classes,每个都提供不同的功能:
System.Timers.Timer
,它触发事件并定期在一个或多个事件接收器中执行代码。 class 旨在用作多线程环境中的 server-based 或服务组件;它没有用户界面,在运行时不可见。System.Threading.Timer
,定时在线程池线程上执行单个回调方法。回调方法在定时器实例化时定义,不能更改。与 System.Timers.Timer class 一样,此 class 旨在用作多线程环境中的 server-based 或服务组件;它没有用户界面,在运行时不可见。System.Windows.Forms.Timer
(仅限 .NET Framework),一种 Windows Forms 组件,它触发事件并定期在一个或多个事件接收器中执行代码。该组件没有用户界面,专为在 single-threaded 环境中使用而设计;它在 UI 线程上执行。System.Web.UI.Timer
(仅限 .NET Framework),一个定期执行异步或同步网页回发的 ASP.NET 组件。
现在您的问题是您很可能正在使用线程计时器。这意味着您需要编组回到 UI 线程 ,因为您无法更新来自 UI 的日期另一个线程。
查看 Jason 的回答