WPF 工具包 DataGrid 多选:如何取出 SelectedItems?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1579700/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
WPF Toolkit DataGrid Multi-Select: How to get SelectedItems out?
提问by Shafique
I'm using the WPF Toolkit's DataGrid. I've enabled the property on the DataGrid to allow for multi-selecting of rows. How do I get the SelectedItems out? I'm using an MVVM framework to bind my ViewModel to my View.
我正在使用 WPF 工具包的 DataGrid。我已启用 DataGrid 上的属性以允许多选行。如何取出 SelectedItems?我正在使用 MVVM 框架将我的 ViewModel 绑定到我的视图。
Thanks!
谢谢!
回答by samneric
Taking Bill's answer, merging options 1 and 2, adding a sprinkling of attached properties as an alternative to writing code-behind, I came up with a Behavior.
根据 Bill 的回答,合并选项 1 和 2,添加少量附加属性作为编写代码隐藏的替代方法,我想出了一个 Behavior。
Firstly, we have the behavior:
首先,我们有以下行为:
Public Class SelectedItemsBehavior
Public Shared ReadOnly SelectedItemsChangedHandlerProperty As DependencyProperty =
DependencyProperty.RegisterAttached("SelectedItemsChangedHandler",
GetType(mvvm.RelayCommand), GetType(SelectedItemsBehavior),
New FrameworkPropertyMetadata(New PropertyChangedCallback(AddressOf OnSelectedItemsChangedHandlerChanged)))
Public Shared Function GetSelectedItemsChangedHandler(ByVal element As DependencyObject) As mvvm.RelayCommand
If element Is Nothing Then Throw New ArgumentNullException("element")
Return element.GetValue(SelectedItemsChangedHandlerProperty)
End Function
Public Shared Sub SetSelectedItemsChangedHandler(ByVal element As DependencyObject, ByVal value As mvvm.RelayCommand)
If element Is Nothing Then Throw New ArgumentNullException("element")
element.SetValue(SelectedItemsChangedHandlerProperty, value)
End Sub
Private Shared Sub OnSelectedItemsChangedHandlerChanged(d As DependencyObject,
e As DependencyPropertyChangedEventArgs)
Dim dataGrid As DataGrid = DirectCast(d, DataGrid)
If e.OldValue Is Nothing AndAlso e.NewValue IsNot Nothing Then
AddHandler dataGrid.SelectionChanged, AddressOf ItemsControl_SelectionChanged
End If
If e.OldValue IsNot Nothing AndAlso e.NewValue Is Nothing Then
RemoveHandler dataGrid.SelectionChanged, AddressOf ItemsControl_SelectionChanged
End If
End Sub
Public Shared Sub ItemsControl_SelectionChanged(sender As Object,
e As SelectionChangedEventArgs)
Dim dataGrid As DataGrid = DirectCast(sender, DataGrid)
Dim itemsChangedHandler As RelayCommand = GetSelectedItemsChangedHandler(dataGrid)
itemsChangedHandler.Execute(dataGrid.SelectedItems)
End Sub
End Class
C#:
C#:
using Microsoft.VisualBasic;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
public class SelectedItemsBehavior
{
public static readonly DependencyProperty SelectedItemsChangedHandlerProperty = DependencyProperty.RegisterAttached("SelectedItemsChangedHandler", typeof(mvvm.RelayCommand), typeof(SelectedItemsBehavior), new FrameworkPropertyMetadata(new PropertyChangedCallback(OnSelectedItemsChangedHandlerChanged)));
public static mvvm.RelayCommand GetSelectedItemsChangedHandler(DependencyObject element)
{
if (element == null)
throw new ArgumentNullException("element");
return element.GetValue(SelectedItemsChangedHandlerProperty);
}
public static void SetSelectedItemsChangedHandler(DependencyObject element, mvvm.RelayCommand value)
{
if (element == null)
throw new ArgumentNullException("element");
element.SetValue(SelectedItemsChangedHandlerProperty, value);
}
private static void OnSelectedItemsChangedHandlerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
DataGrid dataGrid = (DataGrid)d;
if (e.OldValue == null && e.NewValue != null) {
dataGrid.SelectionChanged += ItemsControl_SelectionChanged;
}
if (e.OldValue != null && e.NewValue == null) {
dataGrid.SelectionChanged -= ItemsControl_SelectionChanged;
}
}
public static void ItemsControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
DataGrid dataGrid = (DataGrid)sender;
RelayCommand itemsChangedHandler = GetSelectedItemsChangedHandler(dataGrid);
itemsChangedHandler.Execute(dataGrid.SelectedItems);
}
}
Then we add it to the datagrid in XAML:
然后我们将它添加到 XAML 中的数据网格:
<DataGrid AutoGenerateColumns="False" FontFamily="Tahoma" FontSize="9"
ItemsSource="{Binding Path=ResultsVM}"
mvvm:SelectedItemsBehavior.SelectedItemsChangedHandler="{Binding Path=ResultsSelectionChangedCommand}" />
Then we code the RelayCommand in the ViewModel:
然后我们在 ViewModel 中对 RelayCommand 进行编码:
Public ReadOnly Property ResultsSelectionChangedCommand() As mvvm.RelayCommand
Get
If _resultsSelectionChangedCommand Is Nothing Then
_resultsSelectionChangedCommand = New mvvm.RelayCommand(AddressOf ResultsSelectionChanged)
End If
Return _resultsSelectionChangedCommand
End Get
End Property
Public Sub ResultsSelectionChanged(ByVal selectedItems As Object)
_resultsSelectedItems.Clear()
For Each item In selectedItems
_resultsSelectedItems.Add(item)
Next
End Sub
C#:
C#:
public mvvm.RelayCommand ResultsSelectionChangedCommand {
get {
if (_resultsSelectionChangedCommand == null) {
_resultsSelectionChangedCommand = new mvvm.RelayCommand(ResultsSelectionChanged);
}
return _resultsSelectionChangedCommand;
}
}
public void ResultsSelectionChanged(object selectedItems)
{
_resultsSelectedItems.Clear();
foreach (item in selectedItems) {
_resultsSelectedItems.Add(item);
}
}
The _resultsSelectedItems is simply a list of items displayed in the DataGrid:
_resultsSelectedItems 只是显示在 DataGrid 中的项目列表:
Private _resultsSelectedItems As New List(Of WorkOrderMatchViewModel)
C#:
C#:
private List<WorkOrderMatchViewModel> _resultsSelectedItems = new List<WorkOrderMatchViewModel>();
Hope this helps, kinda uses both of Bill's methods without having to reference MVVM-Light.
希望这会有所帮助,有点使用 Bill 的两种方法,而不必参考 MVVM-Light。
回答by Bill Campbell
I've been looking for an answer to this question as well. The answers that I have found is either to
我也一直在寻找这个问题的答案。我找到的答案是
1) in the codebehind delegate the work to a method in the ViewModel passing the SelectedItems
list from the datagrid. This collection will contain all of the items that are selected.
1) 在代码隐藏中,将工作委托给 ViewModel 中的一个方法,该方法SelectedItems
从数据网格传递列表。此集合将包含所有选定的项目。
Or
或者
2) use the MVVM toolkit light that allows you to use Event to Command and pass an object as a parameter directly to the ViewModel.
2) 使用 MVVM 工具包灯,它允许您使用 Event to Command 并将对象作为参数直接传递给 ViewModel。
private void DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
IList lst = this.myDataGrid.SelectedItems;
ViewModel.RowsSelected(lst);
}
In this case you will need to bind your SelectionChanged
in your xaml to your selectionchanged
in the code behind. Then in your code-behind you can save this list and use it for deleting selected rows, etc.
在这种情况下,您需要将SelectionChanged
xaml 中的内容绑定到selectionchanged
后面的代码中。然后在您的代码隐藏中,您可以保存此列表并将其用于删除选定的行等。
If there is a better way to do this, I'd love to know is well.
如果有更好的方法来做到这一点,我很想知道。
HTH
HTH
Bill
账单
回答by windflavour
C# version SelectedItemsBehavior class. May be help someone.
C# 版本 SelectedItemsBehavior 类。可能会帮助某人。
public static class SelectedItemsBehavior
{
public static readonly DependencyProperty SelectedItemsChangedHandlerProperty =
DependencyProperty.RegisterAttached("SelectedItemsChangedHandler",
typeof(RelayCommand),
typeof(SelectedItemsBehavior),
new FrameworkPropertyMetadata(new PropertyChangedCallback(OnSelectedItemsChangedHandlerChanged)));
public static RelayCommand GetSelectedItemsChangedHandler(DependencyObject element)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
return element.GetValue(SelectedItemsChangedHandlerProperty) as RelayCommand;
}
public static void SetSelectedItemsChangedHandler(DependencyObject element, RelayCommand value)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
element.SetValue(SelectedItemsChangedHandlerProperty, value);
}
public static void OnSelectedItemsChangedHandlerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
DataGrid dataGrid = (DataGrid)d;
if (e.OldValue == null && e.NewValue != null)
{
dataGrid.SelectionChanged += new SelectionChangedEventHandler(ItemsControl_SelectionChanged);
}
if (e.OldValue != null && e.NewValue == null)
{
dataGrid.SelectionChanged -= new SelectionChangedEventHandler(ItemsControl_SelectionChanged);
}
}
public static void ItemsControl_SelectionChanged(Object sender, SelectionChangedEventArgs e)
{
DataGrid dataGrid = (DataGrid)sender;
RelayCommand itemsChangedHandler = GetSelectedItemsChangedHandler(dataGrid);
itemsChangedHandler.Execute(dataGrid.SelectedItems);
}
}
回答by Wilson
I managed to get around this using Relay Commands as Bill mentioned. It is a little dirty in parts, but I avoided putting any code in the behind file.
正如比尔提到的那样,我设法使用中继命令解决了这个问题。它的某些部分有点脏,但我避免在后台文件中放置任何代码。
Firstly, in your XAML - Bind your command onto a button, or whatever triggers your RelayCommand.
首先,在你的 XAML 中 - 将你的命令绑定到一个按钮上,或者任何触发你的 RelayCommand 的东西。
<Button Content="Select"
cmd:ButtonBaseExtensions.Command="{Binding CommandSelect}"
cmd:ButtonBaseExtensions.CommandParameter="{Binding ElementName=Results, Path=SelectedItems}" />
You'll notice the command parameter Binds to another UI element - the DataGrid or ListView you wish to get the selected items of. This syntax will work in Silverlight 3 as well as WPF, as it now supports element to element binding.
您会注意到命令参数绑定到另一个 UI 元素 - 您希望从中获取所选项目的 DataGrid 或 ListView。此语法适用于 Silverlight 3 和 WPF,因为它现在支持元素到元素的绑定。
In your view model your Command will look something like this
在您的视图模型中,您的命令看起来像这样
Private _CommandSelect As RelayCommand(Of IEnumerable)
Public ReadOnly Property CommandSelect() As RelayCommand(Of IEnumerable)
Get
If _CommandSelect Is Nothing Then
_CommandSelect = New RelayCommand(Of IEnumerable)(AddressOf CommandSelectExecuted, AddressOf CommandSelectCanExecute)
End If
Return _CommandSelect
End Get
End Property
Private Function CommandSelectExecuted(ByVal parameter As IEnumerable) As Boolean
For Each Item As IElectoralAreaNode In parameter
Next
Return True
End Function
Private Function CommandSelectCanExecute() As Boolean
Return True
End Function
The Selected Items will be returned as a SelectedItemCollection, but you probably don't want this dependancy in your View Model. So typing it as IEnumerable and doing a little casting is your only option, hense the 'dirtyness'. But it keeps your code behind clean and MVVM pattern in tact!
Selected Items 将作为 SelectedItemCollection 返回,但您可能不希望在您的视图模型中存在这种依赖性。因此,将其输入为 IEnumerable 并进行一些转换是您唯一的选择,从而避免“肮脏”。但它使您的代码保持干净和 MVVM 模式!