[英]Can you set SelectedItems on a DataGrid via a list
我将此代码放在按钮附加的TargetedTriggerAction <DataGrid>中
我要做的是找到我想要的项目并将它们放入列表中。 一旦完成,我想用列表设置DataGrid的SelectedItems。
我想这样做,因为我有成千上万的项目要迭代,在后台线程上做多数并在最后设置SelectedItems,避免使用对SelectedItems.Add()的单一调用的UI线程将更多高效。 无论如何,这是我的逻辑。
我意识到SelecteedItems是只读的所以我的问题是我能真正做到这一点吗? 如何通过列表设置SelectedItems? 另一方面,如果SelectAll按钮可以在短时间内选择所有内容,那么必须有一种方法可以实现我想要的......不应该在那里吗?
IList<Object> tempItems = new List<Object>();
var itemsSource = this.Target.Items as IEnumerable;
Task.Factory.StartNew(() =>
{
FullTextSearch<UserViewModel>.FullTextSearchInit();
if (itemsSource != null)
{
foreach (var item in itemsSource)
{
if (FullTextSearch<UserViewModel>.Match((UserViewModel)item, sv))
{
tempItems.Add(item);
}
}
if (tempItems.Count > 0)
{
Application.Current.Dispatcher.Invoke(new Action(() =>
/**** How to set? ****/
this.Target.SelectedItems = tempList
));
}
}
});
[编辑]尝试执行以下操作,但是,IsUpdatingSelectedItems,BeginUpdateSelectedItems和EndUpdateSelectedItems都返回了类似的错误:
由于其保护级别,System.Windows.Controls.Primitives.MultiSelector.BeginUpdateSelectedItems()'无法访问
if (!this.Target.IsUpdatingSelectedItems)
{
this.Target.BeginUpdateSelectedItems();
foreach (object item in this.Target.Items)
{
if (FullTextSearch<UserViewModel>.Match((UserViewModel)item, sv))
{
this.Target.SelectedItems.Add(item);
}
}
this.Target.EndUpdateSelectedItems();
}
在评论和编辑的问题中,已经询问如何调用DataGrid的受保护的BeginUpdateSelectedItems和EndUpdateSelectedItems方法。
最简单的方法是继承DataGrid并实现一个可以调用这些受保护方法的方法:
public class MyDataGrid : DataGrid
{
public void SelectManyItems(IEnumerable itemsToBeSelected)
{
if (!IsUpdatingSelectedItems)
{
BeginUpdateSelectedItems();
foreach (object item in itemsToBeSelected)
SelectedItems.Add(item);
EndUpdateSelectedItems.Invoke();
}
}
}
虽然这看起来很简单,但它的缺点是需要您在需要此功能的任何地方使用MyDataGrid替换DataGrid 。 在处理现有或第三方代码库时,这种方法很快变得不可行。
另一种更通用的方法是利用反射从DataGrid对象实例的“外部”调用受保护的方法。 这不需要对DataGrid进行子类化。
public static class MultiSelectorHelper
{
private static readonly PropertyInfo _piIsUpdatingSelectedItems;
private static readonly MethodInfo _miBeginUpdateSelectedItems;
private static readonly MethodInfo _miEndUpdateSelectedItems;
static MultiSelectorHelper()
{
_piIsUpdatingSelectedItems = typeof(MultiSelector).GetProperty("IsUpdatingSelectedItems", BindingFlags.NonPublic | BindingFlags.Instance);
_miBeginUpdateSelectedItems = typeof(MultiSelector).GetMethod("BeginUpdateSelectedItems", BindingFlags.NonPublic | BindingFlags.Instance);
_miEndUpdateSelectedItems = typeof(MultiSelector).GetMethod("EndUpdateSelectedItems", BindingFlags.NonPublic | BindingFlags.Instance);
}
public static void SelectManyItems(this MultiSelector control, IEnumerable itemsToBeSelected)
{
control.Dispatcher.Invoke(
(Action) (() =>
{
if (!(bool) _piIsUpdatingSelectedItems.GetValue(control, null))
{
_miBeginUpdateSelectedItems.Invoke(control, null);
try
{
foreach (object item in itemsToBeSelected)
control.SelectedItems.Add(item);
}
finally
{
_miEndUpdateSelectedItems.Invoke(control, null);
}
}
})
);
}
}
请注意, SelectManyItems是作为扩展方法实现的,处理从MultiSelector (包括DataGrid)派生的任何控件。
还要注意try - finally块,它确保即使在添加所选项期间发生异常时也要调用EndUpdateSelectedItems方法。
使用此扩展方法很简单:
IEnumerable collectionWithItemsToSelect = ...
dataGridInstance.SelectManyItems(collectionWithItemsToSelect);
你可以在SelectionChanged()
获得Selecteditems
XAML:
<Window x:Class="ListViewSelectedItemsBinding.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ListViewSelectedItemsBinding"
xmlns:w="clr-namespace:System.Windows.Workarounds"
x:Name="root" Width="500" Height="700">
<Window.Resources>
<local:MyConverter x:Key="myConverter"/>
</Window.Resources>
<StackPanel>
<ListView x:Name="listView" ItemsSource="{Binding}" SelectionMode="Extended"
SelectionChanged="listView_SelectionChanged"
w:ListView.HasBindableSelectedItems="True">
<ListView.View>
<GridView>
<GridViewColumn Header="Artist" DisplayMemberBinding="{Binding Path=Artist}" />
<GridViewColumn Header="Title" DisplayMemberBinding="{Binding Path=Title}" />
<GridViewColumn Header="Genre" DisplayMemberBinding="{Binding Path=Genre}" />
</GridView>
</ListView.View>
</ListView>
<StackPanel Background="LightGreen">
<DockPanel>
<Label DockPanel.Dock="Left" Content="SelectedItems.Count = " />
<TextBox Text="{Binding ElementName=listView, Path=SelectedItems.Count, Mode=OneWay}" IsReadOnly="True" />
</DockPanel>
<DockPanel>
<Label DockPanel.Dock="Left" Content="SelectedItems = " />
<TextBox Text="{Binding ElementName=listView, Path=SelectedItems, Mode=OneWay,
Converter={StaticResource myConverter}, ConverterParameter='Artist'}" IsReadOnly="True" />
</DockPanel>
</StackPanel>
<StackPanel Background="LightBlue">
<DockPanel>
<Label DockPanel.Dock="Left" Content="Selection.Count = " />
<TextBox Text="{Binding ElementName=root, Path=Selection.Count, Mode=OneWay}" IsReadOnly="True" />
</DockPanel>
<DockPanel>
<Label DockPanel.Dock="Left" Content="Selection = " />
<TextBox Text="{Binding ElementName=root, Path=Selection, Mode=OneWay,
Converter={StaticResource myConverter}, ConverterParameter='Artist'}" IsReadOnly="True" />
</DockPanel>
</StackPanel>
<local:PropertiesPanel x:Name="propertiesPanel1" Background="LightGreen"
Subjects="{Binding ElementName=listView, Path=SelectedItems, Mode=OneWay}" />
<local:PropertiesPanel x:Name="propertiesPanel2" Background="LightBlue"
Subjects="{Binding ElementName=root, Path=Selection, Mode=OneWay}" />
<local:PropertiesPanel x:Name="propertiesPanel3" Background="LightPink"
Subjects="{Binding ElementName=listView, Path=BindableSelectedItems}" />
</StackPanel>
</Window>
背景:
using System;
using System.Collections;
using System.Windows.Data;
using System.Windows.Controls;
namespace System.Windows.Workarounds
{
public static class ListView
{
public static readonly DependencyProperty HasBindableSelectedItemsProperty;
public static readonly DependencyProperty BindableSelectedItemsProperty;
static DependencyProperty SelectionChangedHandlerProperty;
static ListView()
{
BindableSelectedItemsProperty = DependencyProperty.Register("BindableSelectedItems", typeof(IList),typeof(System.Windows.Controls.ListView));
HasBindableSelectedItemsProperty = DependencyProperty.RegisterAttached("HasBindableSelectedItems", typeof(bool),typeof(System.Windows.Controls.ListView), new PropertyMetadata(false));
SelectionChangedHandlerProperty = DependencyProperty.RegisterAttached("SelectionChangedHandler", typeof(SelectionChangedHandler),typeof(System.Windows.Controls.ListView));
}
public static void SetHasBindableSelectedItems(System.Windows.Controls.ListView source, bool value)
{
SelectionChangedHandler Handler = (SelectionChangedHandler)source.GetValue(SelectionChangedHandlerProperty);
if (value && Handler == null)
{
Handler = new SelectionChangedHandler(source);
source.SetValue(SelectionChangedHandlerProperty, Handler);
}
else if (!value && Handler != null)
{
source.ClearValue(SelectionChangedHandlerProperty);
}
}
}
internal class SelectionChangedHandler
{
Binding Binding;
internal SelectionChangedHandler(System.Windows.Controls.ListView owner)
{
Binding = new Binding("SelectedItems");
Binding.Source = owner;
owner.SetBinding(ListView.BindableSelectedItemsProperty, Binding);
owner.SelectionChanged +=new SelectionChangedEventHandler(Owner_SelectionChanged);
}
void Owner_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
System.Windows.Controls.ListView Owner =(System.Windows.Controls.ListView)sender;
BindingOperations.ClearBinding(Owner, ListView.BindableSelectedItemsProperty);
Owner.SetBinding(ListView.BindableSelectedItemsProperty, Binding);
}
}
}
你也可以创建一个dependencyproperty来替换'selecteditems'
http://blog.functionalfun.net/2009/02/how-to-databind-to-selecteditems.html
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.