非表示(仮想化)アイテムのListViewで発行される方法をバインドする方法
-
28-10-2019 - |
質問
WPFアプリケーションで大量のデータを処理する必要があります。
私は大きなコレクションをリストビューに縛り付けました、そして私は ItemContainerStyle
リスト項目の発行されたプロパティを私のオブジェクトとバインドする IsSelected
プロパティ、そのため、アイテムがで選択されたとき ListView
, 、私のオブジェクト」 IsSelected
プロパティもTrueに設定されます。これを行うことで、リストで選択されたオブジェクトのみを簡単にコマンドアウトできます。
アプリがそうでなければ鈍化するため、ListViewでUI仮想化を使用します。しかし、私のコレクション全体のサブセットのみがリストに表示されているため、CTRL+Aを使用してリスト内のすべてのアイテムを選択すると、ロードされたアイテムのみが持っています。 IsSelected
Trueに設定されたプロパティ。見えないアイテム(仮想化されたアイテム)には IsSelected
falseに設定されたプロパティ。これは問題です。リスト内のすべてのアイテムを選択すると、 IsSelected
プロパティは、コレクション内のすべてのアイテムに対してTRUEに設定されています。
問題を説明するためにいくつかのサンプルコードを作成しました。
mainwindow.xaml
<Window x:Class="VirtualizationHelp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" x:Name="wnd">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Button Grid.Row="0" Content="Click me" Click="Button_Click" />
<ListView Grid.Row="1" ItemsSource="{Binding Path=Persons, ElementName=wnd}">
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}"/>
</Style>
</ListView.ItemContainerStyle>
</ListView>
</Grid>
</Window>
mainwindow.xaml.cs
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
namespace VirtualizationHelp
{
public partial class MainWindow : Window
{
List<SelectablePerson> _persons = new List<SelectablePerson>(10000);
public List<SelectablePerson> Persons { get { return _persons; } }
public MainWindow()
{
for (int i = 0; i < 10000; i++)
{
SelectablePerson p = new SelectablePerson() { Name = "Person " + i, IsSelected = false };
_persons.Add(p);
}
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
int count = Persons.Where(p => p.IsSelected == true).Count();
(sender as Button).Content = count.ToString();
}
}
public class SelectablePerson
{
public string Name { get; set; }
public bool IsSelected { get; set; }
public override string ToString()
{
return Name;
}
}
}
フォームの上部のボタンがクリックされると、「発行された」プロパティがtrueに設定されたコレクション内のアイテムをカウントします。あなたが押すときにそれを見ることができます Ctrl+a リスト内のすべてのアイテムを選択するには、選択されたアイテムのみが選択されていることが示されています。
誰かがこの問題を回避する方法を知っていますか?恐ろしいパフォーマンスを得るので、仮想化をオフにすることはできません。
解決
それはあなたの拘束力があると思います。基本的に、ListViewItemを更新/バインディングしています。これにより、リスト全体ではなく、目に見えるもののみが更新されます。私はそれで遊んでいます、今のところあなたはコードバインドを解析することができます。
<Window x:Class="VirtualizationHelp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" x:Name="wnd">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock x:Name="txtSelectedItemsCount"/>
<ListView Grid.Row="1" ItemsSource="{Binding Path=Persons, ElementName=wnd}"
SelectionChanged="ListView_SelectionChanged"/>
</Grid>
</Window>
private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var lv = (ListView) sender;
txtSelectedItemsCount.Text = lv.SelectedItems.Count.ToString();
}