Почему мое событие "myTimer_Elapsed не обновляет метку на моем устройстве? - PullRequest
1 голос
/ 12 июня 2019

Извините, если об этом спросили. Я не мог найти ответ на этот вопрос конкретно, и я застрял. Я изучаю таймеры прямо сейчас. Я программист VBA и увлекаюсь C #.

Я пытаюсь написать кроссплатформенное приложение прямо сейчас, и у меня возникают проблемы с моим событием myTimer.Elapsed из-за обновления метки, как это должно быть.

Я прочитал главу о таймерах в C # Notes for Professionals от goalkicker.com и попытался воспроизвести их таймер обратного отсчета. Я также прочитал Microsoft API для события 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 корректируется, как было проверено в ближайшем окне. Это просто ярлык, который не обновляется.

Ответы [ 2 ]

1 голос
/ 12 июня 2019

используйте BeginInvokeOnMainThread, чтобы заставить ваш код пользовательского интерфейса выполняться в потоке пользовательского интерфейса

private void UpdateTimeLeftLabel(string NumberToDisplay)
    {
        Device.BeginInvokeOnMainThread( () => {
          txtTimeRemaining.Text = "Time left: " + NumberToDisplay;
        });
    }
0 голосов
/ 12 июня 2019

Просто чтобы добавить дополнительную информацию здесь в качестве вспомогательной информации

.NET включает четыре класса с именем Timer, каждый из которых предлагает различные функции:

  • System.Timers.Timer, который запускает событие и выполняет код в одном или нескольких приемниках событий через равные промежутки времени. Класс предназначен для использования в качестве серверного или сервисного компонента в многопоточной среде; он не имеет пользовательского интерфейса и не виден во время выполнения.
  • System.Threading.Timer, который выполняет один метод обратного вызова в потоке пула потоков через равные промежутки времени. Метод обратного вызова определяется, когда создается таймер, и его нельзя изменить. Как и класс System.Timers.Timer, этот класс предназначен для использования в качестве серверного или служебного компонента в многопоточной среде; он не имеет пользовательского интерфейса и не виден во время выполнения.
  • System.Windows.Forms.Timer (только .NET Framework), компонент Windows Forms, который запускает событие и выполняет код в одном или нескольких приемниках событий через равные промежутки времени. Компонент не имеет пользовательского интерфейса и предназначен для использования в однопоточной среде; он выполняется в потоке пользовательского интерфейса.
  • System.Web.UI.Timer (только .NET Framework), компонент ASP.NET, который выполняет асинхронную или синхронную обратную передачу веб-страниц с регулярным интервалом.

Теперь ваша проблема в том, что вы, скорее всего, используете таймер потоков. Это означает, что вам нужно вернуть Marshall в поток UI , поскольку вы не можете обновить UI из другого потока.

См. Ответ Джейсона

...