与 MVVM 同步多选列表框
我有一些数据的两个视图:一个列表视图(现在是 ListBox
,但我一直想切换到 ListView
)和地图上的精美图形表示。在任一视图中,用户都可以单击一个对象,并且该对象将在两个视图中被选中。多选也是可能的,因此每个 ViewModel
实例都有自己的 IsSelected
属性。
目前,我将 ListBoxItem.IsSelected
绑定到 ViewModel.IsSelected
,但这仅在 ListBox
未虚拟化时才能正常工作(请参阅此处)。不幸的是,禁用虚拟化会损害性能,并且我的应用程序变得太慢。
所以我必须再次启用虚拟化。为了维护离屏项目的 ViewModel.IsSelected
属性,我注意到 ListBox
和 ListView
有一个 SelectionChangedListBox/ListView
传播到 ViewModel
。
我的问题是,如何反向传播选择状态? ListBox/ListView
的 SelectedItems
属性是只读的!假设用户单击图形表示中的某个项目,但该项目在列表之外。如果我只是设置ViewModel.IsSelected
,那么ListBox/ListView
将不知道新的选择,因此它将无法取消选择如果用户单击列表中的其他项目,则该项目。我可以从 ViewModel
调用 ListBox.ScrollIntoView
,但是有几个问题:
- 在我的 UI 中,如果两个项目位于尽管它们可能位于
ListBox/ListView
中完全不同的位置,但在图形上位于同一位置。 - 它打破了 ViewModel 隔离(我的 ViewModel 完全不知道 WPF,我想保持这种状态。)
那么,亲爱的 WPF 专家,您有什么想法吗?
编辑:我最终切换到 Infragistics 控件并使用一个丑陋且相当慢的解决方案。关键是,我不再需要答案。
I have two views of some data: a list view (a ListBox
now, but I've been meaning to switch to ListView
) and a fancy graphical representation on a map. In either view the user can click an object and it will be selected in both views. Multiselect is also possible, so each ViewModel
instance has its own IsSelected
property.
Currently I'm binding ListBoxItem.IsSelected
to ViewModel.IsSelected
, but this only works properly if the ListBox
is NOT virtualizing (see here). Unfortunately, disabling virtualization hurts performance and my app has become too slow.
So I have to enable virtualization again. In order to maintain the ViewModel.IsSelected
property of off-screen items, I noticed that ListBox
and ListView
have a SelectionChanged
event that I can (presumably) use to propagate the selection state from the ListBox/ListView
to the ViewModel
.
My question is, how do I propagate selection state in the reverse direction? The SelectedItems
property of ListBox/ListView
is read-only! Suppose the user clicks an item in the graphical representation, but it is off-screen w.r.t. the list. If I just set ViewModel.IsSelected
then the ListBox/ListView
will be unaware of the new selection, and as a consequence it will fail to deselect that item if the user clicks a different item in the list. I could call ListBox.ScrollIntoView
from the ViewModel
, but there are a couple of problems:
- In my UI it's actually possible to select two items with one click if they are in the same location graphically, although they may be located in completely different locations in the
ListBox/ListView
. - It breaks ViewModel isolation (my ViewModel is totally unaware of WPF and I'd like to keep it that way.)
So, my dear WPF experts, any thoughts?
EDIT: I ended up switching to an Infragistics control and using an ugly and rather slow solution. The point is, I no longer need an answer.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您可以创建同步的行为
ListBox.SelectedItems
与 ViewModel 中的集合:可以按如下方式使用此行为:(
请注意,ViewModel 中的
SelectedItems
集合具有被初始化;行为不会设置它,它只会改变它的内容)You can create a Behavior that synchronizes
ListBox.SelectedItems
with a collection in your ViewModel:This behavior can be used as shown below:
(note that the
SelectedItems
collection in your ViewModel has to be initialized; the behavior won't set it, it will only change its content)