通过视图模型将滚动查看器滚动到顶部
我将 ScrollViewer 与 MVVM 模式一起使用,ScrollViewer 包装了项目列表,例如
<ScrollViewer>
<ListView>
<ListView.View>
<GridView>
<GridViewColumn
Header = "Name"
DisplayMemberBinding="{Binding Path=Name}"
/>
</GridView>
</ListView.View>
</ListView>
</ScrollViewer>
listview 的项目绑定到 viewmodel 中的对象集合。我希望每当从集合中添加或删除项目时滚动查看器都会滚动到顶部。
我需要视图模型来触发事件,而不是在视图的代码隐藏中使用 ScrollToTop()
方法。
I am using the ScrollViewer with the MVVM pattern, and a list of items is wrapped by the ScrollViewer, such as
<ScrollViewer>
<ListView>
<ListView.View>
<GridView>
<GridViewColumn
Header = "Name"
DisplayMemberBinding="{Binding Path=Name}"
/>
</GridView>
</ListView.View>
</ListView>
</ScrollViewer>
The items of the listview are bound to a collection of objects in the viewmodel. I want the scrollviewer to scroll to the top whenever a item is added or removed from the collection.
I need the viewmodel to trigger the event, rather than using the ScrollToTop()
method in the code-behind of the view.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
恕我直言,最清晰的方法是通过
AttachedProperty
使用“行为”。AttachedProperty
是一种扩展现有控件功能的机制。首先,创建一个类来保存
AtachedProperty
,例如:此附加属性允许
ScrollViewer
“神奇地”拥有Boolean
类型的新属性,就像 XAML 中的DependencyProperty
一样。例如,如果将此属性绑定到 ViewModel 中的标准属性:(同样,名称由您决定),然后将此
Reset
属性设置为true
,您的ScrollViewer
将滚动到顶部。我已将
AtachedProperty
命名为 AutoScrollToTop,但名称对于此目的并不重要。XAML 类似于:
注意:
my
是ScrollViewerBehavior
类所在的命名空间。例如:xmlns:my="clr-namespace:MyApp.Behaviors"
最后,您在 ViewModel 中唯一需要做的就是设置
Reset = true
就像您的情况一样,当您从集合中添加或删除元素时。IMHO, the clearest way to do this is using a "Behavior" via an
AttachedProperty
. AnAttachedProperty
is a mechanism to extend existing controls functionality.First, create a class to hold the
AtachedProperty
, for instance:This attached property allows a
ScrollViewer
having "magically" a new property of typeBoolean
, acting like aDependencyProperty
in your XAML. If you bind this property to a standard property in your ViewModel, for instance:(again, the name is up to you) and then you set this
Reset
property totrue
, yourScrollViewer
will scroll to top.I have named the
AtachedProperty
as AutoScrollToTop, but the name is not important for this purpose.The XAML will be something like:
Note:
my
is the namespace where yourScrollViewerBehavior
class lives. For example:xmlns:my="clr-namespace:MyApp.Behaviors"
Finally, the only thing you have to do in your ViewModel is to set
Reset = true
when you like, in your case, when you add or remove an element from the collection.创建一个新的 ListView 控件来扩展 Listview 并使用这个新控件
Create a new ListView control which extend Listview and use this new one instead
我也遇到过类似的情况,我需要以编程方式分配 ScrollViewer 的 HorizontalOffset 和 VerticalOffset。恐怕没有直接的绑定机制。我所做的是一种解决方法(相信我,我仍然不喜欢我遵循的方法,但我没有找到任何其他选择)。我的建议如下:
挂钩 ScrollViewer 的 Loaded 事件,将发送者对象强制转换为 ScrollViewer 并将其分配给 DataContext 中的属性(意味着您需要在 DataContext 中保留 ScrollViewer 属性,它将在 UI 中保存 ScrollViewer 的引用)。在 ViewModel 中连接 ObservableCollection 的 CollectionChanged 事件并使用 ScrollViewer 属性,您可以调用 ScrollToTop() 等方法。
这只是一种解决方法。我仍在寻找更好的解决方案。
I have also faced a similar scenario where I needed to assign ScrollViewer's HorizontalOffset and VerticalOffset programmatically. I am afraid there is no direct binding mechanism for this. What I did was a way around (believe me, I still do not like the approach I followed, but I did not find any other option). Here is what I suggest:
Hook the ScrollViewer's Loaded event, cast the sender object to ScrollViewer and assign it to a property in DataContext (Means you need to keep a ScrollViewer propery in DataContext which will hold the reference of ScrollViewer in the UI). Hook up ObservableCollection's CollectionChanged events in ViewModel and using the ScrollViewer property, you can call methods like ScrollToTop() etc.
This is just a way around. I am still looking for better solution.
在 MVVM 中执行此操作的最简单正确方法是在视图模型中创建一个事件并从视图中订阅它。然后,在事件处理程序中调用
ScrollToTop
。例如,每次修改集合时,您都会从视图模型中触发该事件,然后由视图对该事件做出反应并将列表滚动到顶部。
即使这涉及一些隐藏代码并要求视图了解其视图模型的一部分,它也不会违反 MVVM 模式,这与其他解决方法不同。
编辑:但当然,它还可以进一步完善。如果您想避免使用代码隐藏,请查找 DataEventTriggers。如果您不介意代码隐藏但担心内存泄漏,请查找弱事件。
最后,由于您想要的逻辑 100% 与视图相关(每次添加或删除项目时都让 ListView 滚动),您还可以将其实现为行为/附加属性,或扩展 ListView。这可能会变得有点复杂,但我鼓励您考虑一下这些选项。
The simplest correct way to do this in MVVM is by creating an event in your viewmodel and subscribing to it from your view. And then, in the event handler, call
ScrollToTop
.You fire the event from your viewmodel every time your collection is modified, for instance, and then it's up to the view to react to that event and scroll the list to the top.
Even if this involves some code-behind and demands that the view knows part of its viewmodel, it doesn't violate the MVVM pattern, unlike other workarounds.
EDIT: But it can be refined a lot more, of course. If you want to avoid using code-behind, look for DataEventTriggers. If you don't mind about code-behind but are concerned about memory leaks, look for weak events.
And finally, since the logic you want is 100% view-related (have the ListView scroll every time an item is added or removed to it), you could also implement it as a Behavior / attached property, or extending the ListView. That could get a tad more convoluted, but I encourage you to give those options some thought.