Trying to "Pulse" DateTime Updates in WPF App
I apologize up front for the lengthy explication.
I am working on a WPF desktop app (shown below):
Basically there can be 0..n process status items in the list (the items themselves are ListBoxItems rendered using a DataTemplate). Recently, I decided I wanted to provide a "time elapsed" style presentation (n seconds/minutes/hours ago) as an alternative to an absolute DateTime format (mm/dd/yyyy at HH:mm:ss). I've accomplished this by using a MultiBinding to a TextBlock as such:
<TextBlock>
<TextBlock.Text>
<MultiBinding Converter = "{StaticResource timeElapsedConverter}">
<Binding
Path = "StatusDateTime"
/>
<Binding
Source = "{StaticResource propertiesHelper}"
Path = "UserOptions.UseElapsedTimeStamps"
/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
I'll spare you the details of the IMultiValueConverter implementation. The second binding is to a helper class that gets the user's timestamp display preferences (i.e. they can still see absolute DateTime values if they want to). The "StatusDateTime" property to which this TextBlock is otherwise bound is nothing specia开发者_如何学Pythonl; it's just a POCO property in a ViewModel class that fires OnPropertyChanged when set.
This view is synchronized with the system backend every (x) seconds. I'd like to "Pulse" the timestamps during synchronization so that the elapsed time measurements stay accurate but if I just set the StatusDateTime property to its existing value, nothing seems to happen (in the case of the example below, it will just say "Published 6 seconds ago..." until either the process itself is updated on the server side or until the application is loaded a second time).
I tried adding IsAsync="true" to the StatusDateTime binding as suggested in this post, but to no avail.
I also tried falling back to regular binding (non-multi) with Mode="TwoWay" explicity declared and that didn't work either.
I know I could just blow away the list and recreate during synchronization, but that just doesn't seem very elegant when I already have all the data I need loaded into the client.
Update: I tried recreating this basic setup in a Window and it seemed to work just fine. I'm now wondering if this has something to do with the target control being on a Page or part of a DataTemplate.
Any thoughts? Thanks in advance!
The way I accomplished this in my own MVVM based app was to have a simple timer running on my ViewModel that fires OnPropertyChanged
every second for the property I want to keep updated. Here's an example (in IronPython syntax):
self.displayTimer = System.Timers.Timer(1000) #fire every second
self.displayTimer.Elapsed += self.displayTimer_Tick
self.displayTimer.Start()
def displayTimer_Tick(self, sender, event):
self.OnPropertyChanged("StatusDateTime")
This uses a System.Timers.Timer
that executes its callback on a background ThreadPool
thread, so it won't interfere with the Dispatcher.
Ok, so I believe I've figured it out. I left out a key piece of detail that more quickly would've pointed us in the right direction: My DataTemplate
is backed by a CollectionViewSource
. If I call the Refresh() method on the CollectionViewSource
's View
property, the timestamps update as expected. I always forget that changing properties of elements of an ObservableCollection
doesn't necessarily cause the CollectionChanged
event to fire which would thereby prompt the CollectionViewSource
to refresh.
Thanks to all who replied!
精彩评论