Reputation: 3563
In the UserInteractiton class I created an instance of the TestTimer class, in which the timer is located. I run it and I want to display the value of this timer in View, but for some reason nothing is displayed.
View
<Grid>
<TextBlock Name="textTimeMiddle" TextWrapping="Wrap"
Text="{Binding TestTimer.TimeFormat, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>
VievModel
public class UserInteractiton : INotifyPropertyChanged
{
public UserInteractiton()
{
TestTimer = new TestTimer();
}
public TestTimer TestTimer { get; private set; }
}
Model
public class TestTimer : INotifyPropertyChanged
{
private string timeFormat;
public string TimeFormat
{
get { return timeFormat; }
set
{
timeFormat = value;
OnPropertyChanged();
}
}
public TestTimer()
{
StartTimer();
}
public void StartTimer()
{
Timer = new DispatcherTimer();
Timer.Interval = new TimeSpan(0, 0, 1);
Timer.Tick += TimerTick;
Timer.Start();
}
private async void TimerTick(object sender, EventArgs e)
{
await Task.Run(() => TimerCycle());
}
private void TimerCycle()
{
for (;;)
{
if (Seconds > 59)
{
Seconds = 0;
Minutes++;
if (Minutes > 59)
{
Minutes = 0;
Hours++;
if (Hours > 23)
Hours = 0;
}
}
Seconds++;
timeFormat = string.Format("{0:00}:{1:00}:{2:00}",
Hours, Minutes, Seconds);
Thread.Sleep(200);
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName]string prop = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prop));
}
}
Upvotes: 0
Views: 204
Reputation: 71
You should raise INotifyPropertyChanged.PropertyChanged
event to notify view that some properties of your view-model has been changed. The basic implementation of INotifyPropertyChanged
implies that you have a method to raise this event:
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
And you should invoke this method from property's setter to make binding work properly:
private string _timeFormat;
public string TimeFormat
{
get { return _timeFormat; }
private set
{
_timeFormat = value;
OnPropertyChanged(nameof(TimeFormat));
}
}
If you would mark propertyName
parametr with [CallerMemberName] attribute you could ignore passing the argument to OnPropertyChanged
method:
public string TimeFormat
{
get { return _timeFormat; }
private set
{
_timeFormat = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
Full code of your TestTimer
class below:
public class TestTimer : INotifyPropertyChanged
{
private string _timeFormat;
public int Minutes { get; private set; }
public int Seconds { get; private set; }
public int Hours { get; private set; }
public DispatcherTimer Timer { get; private set; }
public string TimeFormat
{
get { return _timeFormat; }
private set
{
_timeFormat = value;
OnPropertyChanged(nameof(TimeFormat));
}
}
public TestTimer()
{
StartTimer();
}
public void StartTimer()
{
Timer = new DispatcherTimer();
Timer.Interval = new TimeSpan(0, 0, 1);
Timer.Tick += TimerTick;
Timer.Start();
}
private async void TimerTick(object sender, EventArgs e)
{
await Task.Run(() => TimerCycle());
}
private void TimerCycle()
{
for (; ; )
{
if (Seconds > 59)
{
Seconds = 0;
Minutes++;
if (Minutes > 59)
{
Minutes = 0;
Hours++;
if (Hours > 23)
Hours = 0;
}
}
Seconds++;
TimeFormat = string.Format("{0:00}:{1:00}:{2:00}",
Hours, Minutes, Seconds);
Thread.Sleep(200);
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Upvotes: 2