2010-02-25 40 views
24

Trong đơn đăng ký của tôi, tôi có ListBox với các mục. Ứng dụng này được viết bằng WPF.Hộp danh sách WPF Cuộn để kết thúc tự động

Làm cách nào để cuộn tự động đến mục được thêm gần đây nhất? Tôi muốn ScrollViewer được chuyển đến cuối danh sách khi mục mới đã được thêm vào.

Có sự kiện nào như ItemsChanged không? (Tôi không muốn sử dụng sự kiện SelectionChanged)

Trả lời

0

Bạn có thể thử ListBox.ScrollIntoView() phương pháp, mặc dù có một số problems trong một số trường hợp ...

Dưới đây là một ví dụ từ Tamir Khason: Auto scroll ListBox in WPF

+0

hai trong số ba liên kết ở đây không tồn tại (và chúng là hai chỉ có tiềm năng để thêm nội dung nào đó hữu ích cho câu hỏi) –

29

Hãy thử cách này:

lstBox.SelectedIndex = lstBox.Items.Count -1 
lstBox.ScrollIntoView(lstBox.SelectedItem) 
+0

Đây chỉ là tùy chọn hợp lệ nếu mục cuối cùng được thêm vào cuối cùng trong danh sách. Nhưng mục cuối cùng được thêm vào có thể được thêm vào ở vị trí 0. – 0xBADF00D

+4

Câu trả lời này phải được chấp nhận! @ 0xBADF00D Nếu đó là trường hợp, bạn chỉ nên làm 'lstBox.SelectedIndex = 0';) – DerpyNerd

+0

Làm việc tốt ngay cả với các mục trùng lặp, cảm ơn. –

4

listBox.ScrollIntoView (listBox.Items [listBox.Items.Count - 1]);

25

Hãy nhớ rằng listBox.ScrollIntoView(listBox.Items[listBox.Items.Count - 1]); chỉ hoạt động nếu bạn không có mục trùng lặp. Nếu bạn có các mục có cùng nội dung, nó sẽ cuộn xuống tìm đầu tiên.

Dưới đây là giải pháp tôi tìm thấy:

ListBoxAutomationPeer svAutomation = (ListBoxAutomationPeer)ScrollViewerAutomationPeer.CreatePeerForElement(myListBox); 

IScrollProvider scrollInterface = (IScrollProvider)svAutomation.GetPattern(PatternInterface.Scroll); 
System.Windows.Automation.ScrollAmount scrollVertical = System.Windows.Automation.ScrollAmount.LargeIncrement; 
System.Windows.Automation.ScrollAmount scrollHorizontal = System.Windows.Automation.ScrollAmount.NoAmount; 
//If the vertical scroller is not available, the operation cannot be performed, which will raise an exception. 
if (scrollInterface.VerticallyScrollable) 
    scrollInterface.Scroll(scrollHorizontal, scrollVertical); 
+0

Cảm ơn bạn. Làm việc hoàn hảo cho tôi. Tôi nghĩ rằng bạn nên loại bỏ chatMessages để một cái gì đó như myListBox. –

+2

Tuyệt vời, cảm ơn. FYI cho những người khác: phải thêm những tài liệu tham khảo cho dự án của bạn: UIAutomationProvider và UIAutomationTypes – BCA

+0

Cuối cùng sau nhiều giờ cố gắng và tìm kiếm xung quanh đây là giải pháp tốt nhất tuyệt đối cho tôi. – ck84vi

22

Cách dễ nhất để làm điều này:

if (VisualTreeHelper.GetChildrenCount(listView) > 0) 
{ 
    Border border = (Border)VisualTreeHelper.GetChild(listView, 0); 
    ScrollViewer scrollViewer = (ScrollViewer)VisualTreeHelper.GetChild(border, 0); 
    scrollViewer.ScrollToBottom(); 
} 

Nó luôn luôn làm việc cho ListView và ListBox kiểm soát. Đính kèm mã này vào sự kiện listView.Items.SourceCollection.CollectionChanged và bạn có hành vi tự động cuộn hoàn toàn tự động.

+1

Các giải pháp khác chỉ đơn giản là không làm việc cho tôi cả. Mã đã được thực hiện (được chứng minh trong gỡ lỗi), nhưng nó không ảnh hưởng đến tình trạng kiểm soát. Điều này làm việc hoàn hảo lần đầu tiên xung quanh. –

+1

Điều này có thể không hoạt động nếu bạn sử dụng một mẫu tùy chỉnh cho 'ListBox' vì vậy hãy cẩn thận. –

+0

Đối với bất kỳ ai muốn biết cách đính kèm vào CollectionChanged vào hộp danh sách của bạn: Sau 'InitializeComponent();' bạn phải thêm '((INotifyCollectionChanged) .Items) .CollectionChanged + = YourListboxCollectionChanged;' – MarkusEgle

14

Giải pháp tốt nhất là sử dụng đối tượng ItemCollection bên trong điều khiển ListBox bộ sưu tập này được thiết kế đặc biệt cho người xem nội dung. Nó có một phương pháp được xác định trước để chọn mục cuối cùng và giữ một tham chiếu vị trí con trỏ ....

myListBox.Items.MoveCurrentToLast(); 
myListBox.ScrollIntoView(myListBox.Items.CurrentItem); 
0

Một cách tiếp cận hơi khác so với những gì được trình bày cho đến nay.

Bạn có thể sử dụng sự kiện ScrollViewerScrollChanged và xem nội dung của số ScrollViewer trở nên lớn hơn.

private void ListBox_OnLoaded(object sender, RoutedEventArgs e) 
{ 
    var listBox = (ListBox) sender; 

    var scrollViewer = FindScrollViewer(listBox); 

    if (scrollViewer != null) 
    { 
     scrollViewer.ScrollChanged += (o, args) => 
     { 
      if (args.ExtentHeightChange > 0) 
       scrollViewer.ScrollToBottom(); 
     }; 
    } 
} 

Điều này tránh một số vấn đề với các ràng buộc để các thay đổi ListBoxItemsSource.

Bạn cũng có thể tìm thấy ScrollViewer mà không giả định rằng ListBox đang sử dụng mẫu điều khiển mặc định.

// Search for ScrollViewer, breadth-first 
private static ScrollViewer FindScrollViewer(DependencyObject root) 
{ 
    var queue = new Queue<DependencyObject>(new[] {root}); 

    do 
    { 
     var item = queue.Dequeue(); 

     if (item is ScrollViewer) 
      return (ScrollViewer) item; 

     for (var i = 0; i < VisualTreeHelper.GetChildrenCount(item); i++) 
      queue.Enqueue(VisualTreeHelper.GetChild(item, i)); 
    } while (queue.Count > 0); 

    return null; 
} 

Sau đó đính kèm này với sự kiện ListBoxLoaded:

<ListBox Loaded="ListBox_OnLoaded" /> 

này có thể dễ dàng sửa đổi để trở thành một tài sản gắn liền, để làm cho nó mục đích tổng quát hơn.

Các vấn đề liên quan