Tôi có ListView
(ảo hóa được bật theo mặc định), trong đó ItemsSource
được liên kết với thuộc tính ObservableCollection<Item>
.ScrollIntoView và ListView với ảo hóa
Khi dữ liệu được điền (thuộc tính được đặt và thông báo được tăng lên), tôi thấy 2 bố cục đột biến trong hồ sơ, thứ hai xảy ra sau khi gọi listView.ScrollIntoView()
.
sự hiểu biết của tôi là:
ListView
tải dữ liệu thông qua ràng buộc và tạoListViewItem
cho các hạng mục trên màn hình, bắt đầu từ chỉ số 0.- Sau đó, tôi gọi
listView.ScrollIntoView()
. - Và bây giờ
ListView
thực hiện lần thứ hai đó (tạoListViewItem
giây).
Làm cách nào để ngăn chặn việc ảo hóa đó xảy ra hai lần (tôi không muốn trước khi xảy ra ScrollIntoView
)?
Tôi đã cố gắng thực hiện repro bằng cách sử dụng 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());
}
}
Debug - Performance Profiler - Application Timeline ... chờ một chút, nút bấm, chờ một chút, đóng cửa sổ. Bạn sẽ thấy 2 bố cục được chuyển với VirtualizingStackPanel
. Mục tiêu của tôi là chỉ có một và tôi không biết làm thế nào.
Vấn đề với repro là để mô phỏng tải (khi tạo ListViewItem
is expensive), nhưng tôi hy vọng nó rõ ràng hơn chứng minh vấn đề bây giờ.
Bạn luôn muốn đưa mục cuối cùng vào chế độ xem khi bộ sưu tập các mục đã được thêm vào giao diện người dùng chưa? Nó không giải quyết được vấn đề của hai layout layout nhưng nếu đó là trường hợp bạn có thể thay đổi cách sắp xếp các mục trước khi thêm chúng vào giao diện người dùng để mục bạn muốn đưa vào xem là mục đầu tiên trong bộ sưu tập – Bijington
@Bijington, bộ sưu tập đã được sắp xếp (theo ngày, không được hiển thị trong mcve), tôi không nên thay đổi thứ tự. Nó có thể là bất kỳ mục nào (trong dự án thực sự nó có nhiều lựa chọn 'ListView', cuộn đến mục được chọn cuối cùng).Lý tưởng nhất là tôi đang tìm cách lưu trữ/khôi phục trạng thái 'ListView' trong ứng dụng MVVM (lựa chọn được xử lý, nhưng vị trí cuộn không được, nó * bằng cách nào đó * được xử lý bằng' ScrollIntoView'), việc ảo hóa đôi đó là loại XY- vấn đề (nhưng tôi ok với 'ScrollIntoView', chỉ de-ảo hóa hai lần là vấn đề). – Sinatr
Tôi giả định nhiều nhưng tôi nghĩ nó đáng được hỏi. Điều này chắc chắn âm thanh như một vấn đề thú vị để giải quyết. Bạn cần phải nói cho 'ListView' đó là vị trí cuộn trước khi tải nội dung của nó bằng cách nào đó. Bạn bằng cách nào đó có thể phân lớp 'ListView' và ngăn hiển thị cho đến khi bạn hoàn thành quá trình tải (có thể là cờ IsLoadingContent) để bạn có thể gán các mục và đánh dấu mục nào cần được chọn và đưa vào xem? – Bijington