Eric
Eric

Reputation: 97565

How can I databind to a constantly-changing property

I have a simple class that represents a timer (simplified for clarity):

public class Timer {
    DateTime startTime;

    // How do I notify the UI that this property is changing?
    public TimeSpan Value {
        get {
            return DateTime.Now - startTime;
        }
    }
    public void Start() {
        startTime = DateTime.Now;
    }
}

And a page containing a TextBlock and an instance of a Timer.

I'd like to databind the TextBlock's Text property to show the Timer.Value. However, this field is obviously changing constantly, so firing PropertyChanged events doesn't seem to make any sense.

Is there some way to indicate that a property is always changing, so that the UI updates as fast as is reasonably possible?

Upvotes: 0

Views: 101

Answers (3)

Eric
Eric

Reputation: 97565

This is what I came up with:

public class ObservableTimer : Timer, INotifyPropertyChanged {
    public event PropertyChangedEventHandler PropertyChanged;
    // some extension methods are being used here
    public PropertyChangedEventArgs pcValue = Property.Changed<ObservableTimer>(t => t.Value);

    DispatcherTimer dTimer;

    public ObservableTimer() {
        dTimer = new DispatcherTimer();
        dTimer.Interval = TimeSpan.FromMilliseconds(50);
        dTimer.Tick += onTimerTick;
        dTimer.Start();
    }

    private void onTimerTick(object sender, EventArgs e) {
        // some extension methods are being used here
        PropertyChanged.Raise(this, pcValue);
    }
}

As described in ChrisF's answer, this uses a timer to periodically fire the PropertyChanged event.

Upvotes: 1

Neelesh
Neelesh

Reputation: 116

Here's what you can do, you have this class right,

public class Timer {
DateTime startTime;

// How do I notify the UI that this property is changing?
public TimeSpan Value {
    get {
        return DateTime.Now - startTime;
    }
}
public void Start() {
    startTime = DateTime.Now;
}

}

First Apply the INotifyPropertyChanged to the property Value.

Now in XAML you might be having a grid. You need to bind the "Datacontext" of the grid to the current instance of your Timer class. for that there are lots of way, the most simple among them is to name the grid say(as RootGrid). Now in the loaded event of the user control:

private void UserControl_Loaded(object sender, RoutedEventArgs e)
    {
       RootGrid.DataContext = this;
    }

Ok Game over, last step is to bind the TextBlock's Text property to your "Value".

<TextBlock Text="{Binding Value}"/>

and above code in XAML, will do it for you.

Upvotes: 0

ChrisF
ChrisF

Reputation: 137108

That's what PropertyChanged is designed to do. The UI should be able to cope with a constantly changing value.

However, to ensure that you don't flood the UI you should use a timer that gives you control over the interval of each tick:

System.Threading.Timer myTimer;

TimerCallback callback = TimerTick;
myTimer = new System.Threading.Timer(callback, null, 0, 1000);

This starts a timer straight away (the 0) which fires every second (the 1000). Your TimerCallback will look something like this:

void TimerTick(object stateInfo)
{
    // Raise property changed event with DateTime.Now
}

Upvotes: 1

Related Questions