对于冗长的解释,我预先表示歉意。
我正在开发 WPF 桌面应用程序(如下所示):
基本上可以有 0..n 个进程列表中的状态项(项本身是使用 DataTemplate 呈现的 ListBoxItems)。最近,我决定提供“时间流逝”样式的演示(n 秒/分钟/小时前)作为绝对日期时间格式(mm/dd/yyyy at HH:mm:ss)的替代方案。我通过使用 MultiBinding 到 TextBlock 来完成此操作:
<TextBlock>
<TextBlock.Text>
<MultiBinding Converter = "{StaticResource timeElapsedConverter}">
<Binding
Path = "StatusDateTime"
/>
<Binding
Source = "{StaticResource propertiesHelper}"
Path = "UserOptions.UseElapsedTimeStamps"
/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
我将不再介绍 IMultiValueConverter 实现的详细信息。第二个绑定是一个帮助程序类,该类获取用户的时间戳显示首选项(即,如果他们愿意,他们仍然可以看到绝对日期时间值)。此 TextBlock 绑定到的“StatusDateTime”属性没有什么特别的;它只是 ViewModel 类中的一个 POCO 属性,在设置时会触发 OnPropertyChanged。
该视图每 (x) 秒与系统后端同步一次。我想在同步期间“脉冲”时间戳,以便经过的时间测量保持准确,但如果我只是将 StatusDateTime 属性设置为其现有值,似乎什么也不会发生(在下面的示例中,它只会说“6 秒前发布...”直到进程本身在服务器端更新或直到第二次加载应用程序)。
我尝试按照 这篇文章,但无济于事。
我还尝试使用显式声明的 Mode="TwoWay" 回退到常规绑定(非多重),但这也不起作用。
我知道我可以在同步期间删除列表并重新创建,但是当我已经将需要的所有数据加载到客户端时,这似乎不太优雅。
更新:我尝试在窗口中重新创建这个基本设置,它似乎工作得很好。我现在想知道这是否与目标控件位于页面或数据模板的一部分有关。
有什么想法吗?提前致谢!
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 special; 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!
发布评论
评论(2)
我在自己的基于 MVVM 的应用程序中完成此操作的方法是在我的 ViewModel 上运行一个简单的计时器,该计时器每秒为我想要保持更新的属性触发
OnPropertyChanged
。下面是一个示例(采用 IronPython 语法):它使用
System.Timers.Timer
在后台ThreadPool
线程上执行回调,因此不会干扰 Dispatcher 。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):This uses a
System.Timers.Timer
that executes its callback on a backgroundThreadPool
thread, so it won't interfere with the Dispatcher.好吧,所以我相信我已经弄清楚了。我遗漏了一个关键细节,这些细节可以更快地为我们指明正确的方向:我的
DataTemplate
由CollectionViewSource
支持。如果我在CollectionViewSource
的View
属性上调用 Refresh() 方法,时间戳会按预期更新。我总是忘记,更改ObservableCollection
元素的属性并不一定会导致CollectionChanged
事件触发,从而提示CollectionViewSource
刷新。感谢所有回复的人!
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 aCollectionViewSource
. If I call the Refresh() method on theCollectionViewSource
'sView
property, the timestamps update as expected. I always forget that changing properties of elements of anObservableCollection
doesn't necessarily cause theCollectionChanged
event to fire which would thereby prompt theCollectionViewSource
to refresh.Thanks to all who replied!