реализация секундомера в wp7 - PullRequest
1 голос
/ 31 декабря 2011

В моем приложении wp7.5 у меня есть блок, где мне нужно показать секундомер (скажем, 30,29,28 ... 1,0).Я пробовал различные реализации для достижения этой цели с использованием классов DispatchTimer и Timer, но ни одна из них не решила мою проблему.

Подход 1. Вот фрагмент кода, который я использовал для DispatchTimer,

DispatcherTimer dt = new DispatcherTimer();
dt.Interval = new TimeSpan(0, 0, 1); // 1 second
dt.Tick += new EventHandler(dt_Tick);

for(int count=0;count<30;count++)
    dt.Start();

void dt_Tick(object sender, EventArgs e)
{
   // my UI control update here
}

в моемРеализация тиковых событий. Я обновляю элемент управления с помощью счетчика времени.Здесь я прочитал несколько вопросов на ту же тему, где тик диспетчера никогда не срабатывает в некоторых сценариях из-за потока пользовательского интерфейса.То же самое произошло со мной, тиковое событие никогда не срабатывало.

Подход 2: Я пытался использовать класс System.Threading.Timer,

Timer timer = new Timer(TimerProc);

for(int count=0;count<30;count++)
    timer.Change(1000, 0);

void TimerProc(object sender)
{
   // my UI control update here
}

Ни один из моих подходов не сработал.Я мог бы задать повторный вопрос, может кто-нибудь указать мне, где я делаю неправильно в коде?

Ответы [ 2 ]

2 голосов
/ 31 декабря 2011

DispatcherTimer после вызова метода Start() keep запускает Tick event по истечении интервала до тех пор, пока вы не вызовете Stop() для него. Таким образом, вам не нужно звонить Start() 30 раз, но вы должны поддерживать счетчик и в обработчике Tick event остановить таймер после 30 тиков:

private int counter;

private void Start_Click(object sender, RoutedEventArgs e)
{
    counter = 30;
    DispatcherTimer dt = new DispatcherTimer();
    dt.Interval = new TimeSpan(0, 0, 1); // 1 second
    dt.Tick += new EventHandler(dt_Tick);
    dt.Start();
}

void dt_Tick(object sender, EventArgs e)
{
    if (counter >= 0)
    {
        timeText.Text = counter.ToString();
        counter--;
    }
    else
        ((DispatcherTimer)sender).Stop();
}

Edit:
Если точность DispatcherTimer недостаточна, вы можете вместо этого использовать System.Threading.Timer , но в этом случае у вас есть вызов Dispatcher.BeginInvoke в обработчике тиковых событий, чтобы разрешить доступ для объектов в потоке пользовательского интерфейса:

private int counter;

private void Start_Click(object sender, RoutedEventArgs e)
{
    counter = 30;
    timeText.Text = counter.ToString();
    Timer dt = new Timer(dt_Tick);
    dt.Change(1000 /* delay to start the timer */, 1000 /* period time */);
}

private void dt_Tick(object sender)
{
    if (counter > 0)
    {
        Dispatcher.BeginInvoke(() => timeText.Text = counter.ToString());
        counter--;
    }
    else
        ((Timer) sender).Dispose();
}
0 голосов
/ 31 декабря 2011

Метод тикового таймера не должен отслеживать время.Зачем?По двум причинам.

1 / Интервал между каждым тиком DispatcherTimer не является точным и зависит от того, что вы делаете с пользовательским интерфейсом.Это может быть 1 секунда, как это может быть немного больше.

2 / Следующий тик срабатывает через одну секунду после окончания предыдущего тика.Поскольку обновление кода внутри галочки занимает некоторое время, оно будет автоматически отставать.Например, если обновление кода занимает 0,1 секунды, тик срабатывает через 1 секунду, обновление завершено, а следующий тик наступает через 1 секунду после окончания обновления, поэтому через 2,1 секунды после запуска таймера!

Следовательно, вы должны хранить время, когда вы запустили Таймер, и вычислять истекшее время для каждого тика:

    protected DispatcherTimer Timer { get; set; }

    protected DateTime TimerStartTime { get; set; }

    private void ButtonStart_Click(object sender, RoutedEventArgs e)
    {
        this.Timer = new DispatcherTimer();
        this.Timer.Interval = TimeSpan.FromSeconds(1);
        this.Timer.Tick += this.Timer_Tick;
        this.TimerStartTime = DateTime.Now;
        this.Timer.Start();
    }

    private void Timer_Tick(object sender, EventArgs e)
    {
        int elapsedSeconds = (int)DateTime.Now.Subtract(this.TimerStartTime).TotalSeconds;

        this.TextTimer.Text = (30 - elapsedSeconds).ToString();
    }

Таким образом, даже если время между каждым тиком не точное,таймер не будет указывать ложное время.Вы можете даже уменьшить интервал таймера до 500 мс или меньше, чтобы иметь более точный таймер, не меняя метод Тика.

...