簡體   English   中英

您可以通過列表在DataGrid上設置SelectedItems

[英]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的受保護的BeginUpdateSelectedItemsEndUpdateSelectedItems方法。

最簡單的方法是繼承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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM