我有ListView
(默认情况下处于虚拟化状态),该ItemsSource
绑定(bind)到ObservableCollection<Item>
属性。
当填充数据(设置属性并发出通知)时,我在探查器中看到2个布局峰值,第二个发生在调用listView.ScrollIntoView()
之后。
我的理解是:
ListView
通过绑定(bind)加载数据,并从索引0开始为屏幕上的项目创建ListViewItem
。listView.ScrollIntoView()
。 ListView
做了第二次(创建ListViewItem
)。 如何防止非虚拟化发生两次(我不想在
ScrollIntoView
之前发生一次)?我尝试使用
ListBox
进行复制。xaml:
<Grid>
<ListBox x:Name="listBox" ItemsSource="{Binding Items}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="IsSelected" Value="{Binding IsSelected}" />
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
<Button Content="Fill" VerticalAlignment="Top" HorizontalAlignment="Center" Click="Button_Click" />
</Grid>
CS:
public class NotifyPropertyChanged : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string property = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
public class ViewModel : NotifyPropertyChanged
{
public class Item : NotifyPropertyChanged
{
bool _isSelected;
public bool IsSelected
{
get { return _isSelected; }
set
{
_isSelected = value;
OnPropertyChanged();
}
}
}
ObservableCollection<Item> _items = new ObservableCollection<Item>();
public ObservableCollection<Item> Items
{
get { return _items; }
set
{
_items = value;
OnPropertyChanged();
}
}
}
public partial class MainWindow : Window
{
ViewModel _vm = new ViewModel();
public MainWindow()
{
InitializeComponent();
DataContext = _vm;
}
void Button_Click(object sender, RoutedEventArgs e)
{
var list = new List<ViewModel.Item>(1234567);
for (int i = 0; i < 1234567; i++)
list.Add(new ViewModel.Item());
list.Last().IsSelected = true;
_vm.Items = new ObservableCollection<ViewModel.Item>(list);
listBox.ScrollIntoView(list.Last());
}
}
调试-Performance Profiler-应用程序时间表...稍等片刻,单击按钮,稍等片刻,关闭窗口。您将看到2个带有
VirtualizingStackPanel
的布局通行证。我的目标是只有一个,但我不知道该怎么做。repro的问题是模拟负载(在创建
ListViewItem
is expensive时),但我希望现在可以更清楚地演示该问题。 最佳答案
Scroll方法通常在VirtualizingStackPanel
上效果不佳。要解决此问题,我使用以下解决方案。
VirtualizingStackPanel
。使用普通的StackPanel作为面板模板。 通过这种方法,我通常可以获得良好的性能。为了使其完全符合您的要求,可能需要向LazyControl添加一些其他逻辑以等待设置一些标志(在调用scroll方法之后)。