The only way to show current time updating regularly I found is to use timer. Of course, I can implement INotifyPropertyChanged
and some special property to be
WPF is a static markup language. As far as I am aware there is not a mechanism available in pure XAML to provide the functionally you are looking for.
If you want to avoid using a timer directly you can abstract it away using Tasks.
MainWindow XAML:
<Window x:Class="AsyncTimer.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:AsyncTimer"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Label Content="{Binding CurrentTime}"></Label>
</Grid>
</Window>
Code behind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new CurrentTimeViewModel();
}
}
public class CurrentTimeViewModel : INotifyPropertyChanged
{
private string _currentTime;
public CurrentTimeViewModel()
{
UpdateTime();
}
private async void UpdateTime()
{
CurrentTime = DateTime.Now.ToString("G");
await Task.Delay(1000);
UpdateTime();
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public string CurrentTime
{
get { return _currentTime; }
set { _currentTime = value; OnPropertyChanged(); }
}
}
This is probably one of the more succinct and certainly as "Modern" WPF you are going to get.
Here is a little code sample that works without a timer:
public DateTime CurrentTime
{
get => DateTime.Now;
}
public CurrentViewModelTime(object sender, RoutedEventArgs e)
{
_ = Update(); // calling an async function we do not want to await
}
private async Task Update()
{
while (true)
{
await Task.Delay(100);
OnPropertyChanged(nameof(CurrentTime)));
}
}
Of course, this Update() function never returns, but it does its loop on a threadpool thread and does not even block any thread for long.
You can perfectly also implement this in the window directly without a viewmodel.
Using Task.Delay can produce an high CPU usage!
In the XAML code write this:
<Label Name="LiveTimeLabel" Content="%TIME%" HorizontalAlignment="Left" Margin="557,248,0,0" VerticalAlignment="Top" Height="55" Width="186" FontSize="36" FontWeight="Bold" Foreground="Red" />
Next in the xaml.cs write this:
[...]
public MainWindow()
{
InitializeComponent();
DispatcherTimer LiveTime = new DispatcherTimer();
LiveTime.Interval = TimeSpan.FromSeconds(1);
LiveTime.Tick += timer_Tick;
LiveTime.Start();
}
void timer_Tick(object sender, EventArgs e)
{
LiveTimeLabel.Content = DateTime.Now.ToString("HH:mm:ss");
}
[...]