Search code examples
c#wpfbindingdispatchertimer

Binding to property not working with DispatcherTimer


I have some TextBlock bound to a property with DependencyProperty. When a DispatcherTimer changes this property, the TextBlock does not update. Even in debugging, I can see that the property get updated, but TextBlock remains unchanged.

Details: I have a class:

    public class myTimer
{
    public System.DateTime Duration { get; set; }
    public System.DateTime Elapsed { get; set; }
    public System.TimeSpan Remaining {
        get {
            return Duration.Subtract(new DateTime(Duration.Year, Duration.Month, Duration.Day, Elapsed.Hour, Elapsed.Minute, Elapsed.Second));
        }
    }
}

I have in my xaml code behind a DependencyProperty of type myTimer

    public static DependencyProperty currentTimerProperty = DependencyProperty.Register("CurrentTimer", typeof(myTimer),  typeof(Question));
    public myTimer CurrentTimer
    {
        get { return (myTimer)GetValue(currentTimerProperty); }
        set { SetValue(currentTimerProperty, value); }
    }

and I have three TextBlock bounded to this property:

    <TextBlock  Style="{StaticResource myTimer}">
         <TextBlock.Text>
               <MultiBinding StringFormat="{}{0:00}:{1:00;00}">
                      <Binding ElementName="Questionctl" Path="CurrentTimer.Remaining.Minutes"/>
                      <Binding ElementName="Questionctl" Path="CurrentTimer.Remaining.Seconds"/>
                </MultiBinding> 
           </TextBlock.Text>
     </TextBlock>
     <TextBlock Text="{Binding ElementName=Questionctl,Path=CurrentTimer.Duration,StringFormat=HH:mm:ss}"/>
     <TextBlock Text="{Binding ElementName=Questionctl,Path=CurrentTimer.Elapsed,StringFormat=HH:mm:ss}"/>

the timer is initialized like this:

dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
dispatcherTimer.Interval = new TimeSpan( 0 , 0, 1);
dispatcherTimer.Start();

so simply, every second, it will add 1 second to the property Elapsed:

CurrentTimer.Elapsed = CurrentTimer.Elapsed.AddSeconds(1);

Solution

  • Update your Class definition of myTimer to implement INotifyPropertyChanged looks like:

    public class myTimer : INotifyPropertyChanged
    {
        private System.DateTime _duration;
    
        public System.DateTime Duration
        {
            get
            {
                return _duration;
            }
            set
            {
                _duration = value;
                RaisePropertyChanged("Duration");
                RaisePropertyChanged("Remaining");
            }
        }
    
        private DateTime _elapsed;
    
        public DateTime Elapsed
        {
            get { return _elapsed; }
            set
            {
                _elapsed = value;
                RaisePropertyChanged("Elapsed");
                RaisePropertyChanged("Remaining");
            }
        }
    
        public System.TimeSpan Remaining
        {
            get
            {
                return Duration.Subtract(new DateTime(Duration.Year, Duration.Month, Duration.Day, Elapsed.Hour, Elapsed.Minute, Elapsed.Second));
            }
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        private void RaisePropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }