Reputation: 182
I'm building a Universal Windows Application which will allow users to track the time spent on a specific task.
On my Mainpage I'm binding an ObservableCollection, containing the time registrations. When a task is running I want to update the time spent every second.
I'm using a DispatcherTimer (whichs runs fine) to update the time spent for all active timers. I have implemented INotifyPropertyChanged and I'm firing the PropertyChanged event in the setter of the property which is binded to my XAML.
The Problem
I'm expecting my UI to update every second but it only updates once - each run - and does so at very irregular timestamps. I think I'm doing something wrong with my binding.
Your help is greatly appreciated!
MainPage_loaded
private async void MainPage_Loaded(object sender, RoutedEventArgs e)
{
TimerRepository repository = new TimerRepository();
this.Timers = await repository.GetTimersAsync();
_timer = new DispatcherTimer();
_timer.Interval = TimeSpan.FromSeconds(1);
_timer.Tick += _timer_Tick;
_timer.Start();
}
Dispatcher Timer, 1 second tick handling:
private void _timer_Tick(object sender, object e)
{
if (this.Timers != null)
{
foreach (var timer in this.Timers.Where(m => m.IsRunning))
{
timer.Tick();
}
}
}
Custom Timer Model
public class SprintTimer : INotifyPropertyChanged
{
private string _name;
private DateTime? _timerStarted;
public event PropertyChangedEventHandler PropertyChanged;
private TimeSpan _registedTime;
public TimeSpan RegisteredTime
{
get
{
return _registedTime;
}
set
{
_registedTime = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("RegisteredTime"));
}
}
public bool IsRunning
{
get
{
return this._timerStarted.HasValue;
}
}
public void Start()
{
if (!this._timerStarted.HasValue)
{
_timerStarted = DateTime.Now;
}
}
public void Tick()
{
if (this.IsRunning)
{
this.RegisteredTime = DateTime.Now - _timerStarted.Value;
}
}
}
XAML
<ScrollViewer BringIntoViewOnFocusChange="False" VerticalScrollBarVisibility="Hidden">
<StackPanel x:Name="stackPanel" Grid.Row="0" Margin="20 20 20 0">
<ItemsControl ItemsSource="{x:Bind Timers, Mode=OneWay}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="data:SprintTimer">
<Grid BorderThickness="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Text="{x:Bind Name}" Grid.Column="0" FontSize="18" VerticalAlignment="Center"></TextBlock>
<TextBlock Text="{x:Bind RegisteredTime}" Grid.Column="1" VerticalAlignment="Center" TextAlignment="Right" FontSize="22" Margin="10"></TextBlock>
<Button Grid.Column="2" VerticalAlignment="Center" Margin="10" Name="btnStartTimer" Click="btnStartTimer_Click">
<SymbolIcon x:Name="icon" Symbol="Play"></SymbolIcon>
</Button>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ScrollViewer>
UI
Upvotes: 1
Views: 161
Reputation: 2067
The default mode of x:Bind is OneTime, you need to add Mode=OneWay
to all the binding expressions.
Upvotes: 2