У меня есть приложение, которое отображает различные аварийные сигналы и состояния. Некоторые аварийные сигналы при срабатывании должны отображать счетчик таймера с момента его активации. Я прочитал несколько реализаций и даже вопросы здесь о SO, но ничего не работает на 100%.Реализация и отображение таймера пользовательского интерфейса с WPF MVVM
Следующее решение подходит ближе всего. Таймер отображается, и он обновляется, но он обновляется только 1 секунду каждые 30-45 секунд. Свойство UI привязано к свойству TimeElapsed, устанавливая свойство TimeStarted - это то, что начинает все.
public class Alarm : INotifyPropertyChanged
{
DispatcherTimer timer = null;
Stopwatch stopWatch = new Stopwatch();
public Alarm()
{
Application.Current.Dispatcher.Invoke(() =>
{
timer = new DispatcherTimer();
timer.Tick += timer_Tick;
timer.Interval = new TimeSpan(0, 0, 1);
}, DispatcherPriority.Normal);
}
private TimeSpan initialDifference;
private DateTime? timeStarted;
public DateTime? TimeStarted
{
get { return timeStarted; }
set
{
// If the value is new
if (timeStarted != value)
{
// If timeStarted was previously null then start the new timer
if (!timeStarted.HasValue)
{
timeStarted = value;
// Get the initial difference between Now and TimeStarted
initialDifference = DateTime.Now.Subtract(TimeStarted.Value);
//irolTimer = new System.Threading.Timer(TickTick, null, 1000, 1000);
Application.Current.Dispatcher.Invoke(() =>
{
stopWatch.Start();
timer.Start();
}, DispatcherPriority.Normal);
}
// If the timeStarted had a value but now its gone (stop the timer)
else if (timeStarted.HasValue && value == null)
{
if (stopWatch.IsRunning)
stopWatch.Stop();
timeStarted = value;
}
// If we already have a timer going but for some reason we just received a different start time
else if (timeStarted.HasValue && value != null)
{
timeStarted = value;
// Change the initial difference
initialDifference = DateTime.Now.Subtract(TimeStarted.Value);
}
OnPropertyChanged("TimeStarted");
}
}
}
private string timeElapsed = string.Empty;
public string TimeElapsed
{
get
{
return timeElapsed;
}
set
{
timeElapsed = value;
OnPropertyChanged("TimeElapsed");
}
}
void timer_Tick(object sender, EventArgs e)
{
if (stopWatch.IsRunning)
{
TimeSpan elapsed = stopWatch.Elapsed;
TimeSpan total = initialDifference + elapsed;
TimeElapsed = String.Format("{0:00}:{1:00}:{2:00}", total.Hours, total.Minutes, total.Seconds/10);
}
}
}
Добавление диспетчера. Включение события Tick приводит к тому, что таймер вообще не отображается. Я пробовал несколько различных реализаций, включая использование обычного System.Threading.Timer без везения. Секундомер казалось излишним, и я думал, что я мог бы сделать то же самое со следующим, но она заставила его прекратить работу:
TimeElapsed = DateTime.Now.Subtract(TimeStarted.Value).ToString("hh:mm:ss");
Вот скриншот, я должен был изменить его из-за соображений безопасности, но я пытался добавьте текст для контекста. Элемент, обведенный красным цветом, является текстом таймера. Xaml прямо вперед следующим образом:
<StackPanel DockPanel.Dock="Left">
<TextBlock FontSize="18" Text="{Binding Path=DisplayName, IsAsync=True}" Style="{StaticResource Alarm}" Foreground="White" FontWeight="Bold" Padding="2,2,2,2" />
<TextBlock Text="{Binding Path=TimeElapsed, IsAsync=True}" Foreground="White" FontSize="12" FontWeight="Bold" />
</StackPanel>
Сыр печенья!/10 - вот почему я получал нечетную задержку в скорости обновления. Я видел эту строку кода в 100 раз и более и никогда не думал, чтобы спросить, почему в мире секунды были разделены на 10. – jrandomuser