我有ListView
(默认情况下虚拟化处于启用状态),ItemsSource
绑定到ObservableCollection<Item>
属性。
填充数据时(设置属性并提高通知)我在分析器中看到2个布局峰值,第二个在调用listView.ScrollIntoView()
后发生。
我的理解是:
ListView
通过绑定加载数据,并为屏幕上的项创建ListViewItem
,从索引0开始。listView.ScrollIntoView()
。ListView
第二次(创建ListViewItem
s)。如何防止去虚拟化发生两次(我不想在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());
}
}
调试 - 性能分析器 - 应用程序时间线...稍等一下,单击按钮,稍等一下,关闭窗口。您将看到VirtualizingStackPanel
的2个布局传递。我的目标是只有一个,我不知道如何。
repro的问题是模拟加载(创建ListViewItem
is expensive时),但我希望现在能更清楚地证明这个问题。
答案 0 :(得分:-1)
Scroll方法通常不能在VirtualizingStackPanel
上运行良好。为了解决这个问题,我使用以下解决方案。
VirtualizingStackPanel
。使用正常的StackPanel作为面板模板。我通常会从这种方法中获得良好的表现。为了使它完全符合您的要求,您可能需要向LazyControl添加一些额外的逻辑以等待设置某个标志(在您调用scroll方法之后)。