WPF M-V-VM:从ListCollectionView获取选定的项? [英] WPF M-V-VM: Get selected items from a ListCollectionView?
问题描述
我有一个使用Model-View-ViewModel模式的WPF应用程序.
在我的ViewModel中,我有一个ListCollectionView来保存项目列表.
此ListCollectionView绑定到我的视图中的ListBox.
I've got a WPF app using the Model-View-ViewModel pattern.
In my ViewModel I've got a ListCollectionView to keep a list of items.
This ListCollectionView is bound to a ListBox in my View.
<ListBox Grid.Row="1" ItemsSource="{Binding Useragents}" SelectionMode="Multiple"/>
ListBox的SelectionMode = Multiple,因此您可以一次选择更多项.现在,ViewModel需要知道已选择了哪些项目.
The ListBox has SelectionMode=Multiple, so you can select more items at one time. Now the ViewModel needs to know which items has been selected.
问题是:在View-Model-ViewModel模式中,ViewModel无法访问View,因此我不能只问ListBox选中了哪些项目.我只有ListCollectionView,但是找不到在其中选择了哪些项目的方法.
The problem is: in the View-Model-ViewModel pattern the ViewModel has no access to the View, so I can't just ask the ListBox which items has been selected. All I have is the ListCollectionView, but I can't find a way to find which items has been selected in there.
那么我如何找到在列表框中选择了哪些项目?或达到此目的的技巧(也许将某些项绑定到我项目中的布尔值"IsSelected"上?但是怎么办?如何做?)
So how do I find which items has been selected in the ListBox? Or a trick to achieve this (maybe bind something to a Boolean 'IsSelected' in my items? But what? How?)
也许有人也在使用这种模式,可以在这里帮助我吗?
Maybe someone who is using this pattern, too, can help me here?
推荐答案
PRISM MVVM参考实现具有一种称为SynchronizeSelectedItems的行为,在Prism4 \ MVVM RI \ MVVM.Client \ Views \ MultipleSelectionView.xaml中使用,该行为将选中的项与名为Selections
的ViewModel属性同步:
PRISM MVVM Reference Implementation has a behaviour called SynchronizeSelectedItems, used in Prism4\MVVM RI\MVVM.Client\Views\MultipleSelectionView.xaml, which synchronizes checked items with the ViewModel property named Selections
:
<ListBox Grid.Column="0" Grid.Row="1" IsTabStop="False" SelectionMode="Multiple"
ItemsSource="{Binding Question.Range}" Margin="5">
<ListBox.ItemContainerStyle>
<!-- Custom style to show the multi-selection list box as a collection of check boxes -->
<Style TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Grid Background="Transparent">
<CheckBox IsChecked="{Binding IsSelected, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"
IsHitTestVisible="False" IsTabStop="True"
AutomationProperties.AutomationId="CheckBoxAutomationId">
<ContentPresenter/>
</CheckBox>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
<i:Interaction.Behaviors>
<!-- Custom behavior that synchronizes the selected items with the view models collection -->
<Behaviors:SynchronizeSelectedItems Selections="{Binding Selections}"/>
</i:Interaction.Behaviors>
</ListBox>
转到 http://compositewpf.codeplex.com/并全部抓取或使用以下方法:
Go to http://compositewpf.codeplex.com/ and grab it all or use this:
//===================================================================================
// Microsoft patterns & practices
// Composite Application Guidance for Windows Presentation Foundation and Silverlight
//===================================================================================
// Copyright (c) Microsoft Corporation. All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===================================================================================
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious. No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
//===================================================================================
using System;
using System.Collections;
using System.Collections.Specialized;
using System.Diagnostics.CodeAnalysis;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;
namespace MVVM.Client.Infrastructure.Behaviors
{
/// <summary>
/// Custom behavior that synchronizes the list in <see cref="ListBox.SelectedItems"/> with a collection.
/// </summary>
/// <remarks>
/// This behavior uses a weak event handler to listen for changes on the synchronized collection.
/// </remarks>
public class SynchronizeSelectedItems : Behavior<ListBox>
{
public static readonly DependencyProperty SelectionsProperty =
DependencyProperty.Register(
"Selections",
typeof(IList),
typeof(SynchronizeSelectedItems),
new PropertyMetadata(null, OnSelectionsPropertyChanged));
private bool updating;
private WeakEventHandler<SynchronizeSelectedItems, object, NotifyCollectionChangedEventArgs> currentWeakHandler;
[SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly",
Justification = "Dependency property")]
public IList Selections
{
get { return (IList)this.GetValue(SelectionsProperty); }
set { this.SetValue(SelectionsProperty, value); }
}
protected override void OnAttached()
{
base.OnAttached();
this.AssociatedObject.SelectionChanged += this.OnSelectedItemsChanged;
this.UpdateSelectedItems();
}
protected override void OnDetaching()
{
this.AssociatedObject.SelectionChanged += this.OnSelectedItemsChanged;
base.OnDetaching();
}
private static void OnSelectionsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var behavior = d as SynchronizeSelectedItems;
if (behavior != null)
{
if (behavior.currentWeakHandler != null)
{
behavior.currentWeakHandler.Detach();
behavior.currentWeakHandler = null;
}
if (e.NewValue != null)
{
var notifyCollectionChanged = e.NewValue as INotifyCollectionChanged;
if (notifyCollectionChanged != null)
{
behavior.currentWeakHandler =
new WeakEventHandler<SynchronizeSelectedItems, object, NotifyCollectionChangedEventArgs>(
behavior,
(instance, sender, args) => instance.OnSelectionsCollectionChanged(sender, args),
(listener) => notifyCollectionChanged.CollectionChanged -= listener.OnEvent);
notifyCollectionChanged.CollectionChanged += behavior.currentWeakHandler.OnEvent;
}
behavior.UpdateSelectedItems();
}
}
}
private void OnSelectedItemsChanged(object sender, SelectionChangedEventArgs e)
{
this.UpdateSelections(e);
}
private void UpdateSelections(SelectionChangedEventArgs e)
{
this.ExecuteIfNotUpdating(
() =>
{
if (this.Selections != null)
{
foreach (var item in e.AddedItems)
{
this.Selections.Add(item);
}
foreach (var item in e.RemovedItems)
{
this.Selections.Remove(item);
}
}
});
}
private void OnSelectionsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
this.UpdateSelectedItems();
}
private void UpdateSelectedItems()
{
this.ExecuteIfNotUpdating(
() =>
{
if (this.AssociatedObject != null)
{
this.AssociatedObject.SelectedItems.Clear();
foreach (var item in this.Selections ?? new object[0])
{
this.AssociatedObject.SelectedItems.Add(item);
}
}
});
}
private void ExecuteIfNotUpdating(Action execute)
{
if (!this.updating)
{
try
{
this.updating = true;
execute();
}
finally
{
this.updating = false;
}
}
}
}
}
这篇关于WPF M-V-VM:从ListCollectionView获取选定的项?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!