2016-07-11 35 views
13

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à:

  1. ListView tải dữ liệu thông qua ràng buộc và tạo ListViewItem cho các hạng mục trên màn hình, bắt đầu từ chỉ số 0.
  2. Sau đó, tôi gọi listView.ScrollIntoView().
  3. Và bây giờ ListView thực hiện lần thứ hai đó (tạo ListViewItem 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 ListViewItemis expensive), nhưng tôi hy vọng nó rõ ràng hơn chứng minh vấn đề bây giờ.

+0

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

+0

@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

+0

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

Trả lời

0

Phương pháp cuộn thường không hoạt động tốt trên VirtualizingStackPanel. Để làm việc xung quanh tôi sử dụng giải pháp sau đây.

  1. Mương số VirtualizingStackPanel. Đi với một StackPanel bình thường cho mẫu bảng điều khiển.
  2. Làm cho lớp ngoài của DataTemplate của bạn là LazyControl từ đây: http://blog.angeloflogic.com/2014/08/lazycontrol-in-junglecontrols.html
  3. Đảm bảo bạn đặt chiều cao trên LazyControl đó.

Tôi thường có hiệu suất tốt trong cách tiếp cận đó. Để làm cho nó làm chính xác những gì bạn đang yêu cầu, bạn có thể cần phải thêm một số logic bổ sung cho LazyControl để chờ đợi cho một số cờ được thiết lập (sau khi bạn gọi phương thức cuộn).