2009-05-13 28 views
11

Tôi có một WPF ListBox được liên kết với một số ObservableCollection. Khi mọi thứ được thêm vào bộ sưu tập, vị trí di chuyển ListBox sẽ thay đổi theo kích thước của các mục được thêm vào. Tôi muốn có thể duy trì vị trí cuộn, để ngay cả khi mọi thứ được thêm vào danh sách, các mục hiện đang xem không di chuyển. Có cách nào để hoàn thành nó không?Bảo quản vị trí cuộn của Hộp danh sách WPF bị ràng buộc khi bộ sưu tập thay đổi

+0

Tôi chỉ thực hiện một dữ liệu wpf thực sự đơn giản với một hộp danh sách và khi tôi thêm các mục mà các mục được xem trong chế độ xem ở chế độ xem ... Bạn đang làm gì khác? – TheCodeMonk

+0

Hãy thử thêm các mục mới vào phần mở rộng của bộ sưu tập. Các mục bạn đang xem bắt đầu di chuyển ra khỏi chế độ xem vì các mục mới được thêm vào. Bạn thêm 1 mục - viewport vẫn ở cùng một vị trí (dựa trên chỉ mục) có nghĩa là 1 mục được nhập vào khung nhìn và 1 mục còn lại. – EvAlex

Trả lời

0

Tôi không chắc chắn nếu có ghi đè cho điều đó, nhưng tôi nghi ngờ điều đó.

Khi nghi ngờ sử dụng tính năng ràng buộc thủ công? : -} Nghiêm túc, hành vi ràng buộc mặc định sẽ là - tốt - mặc định, vì vậy nếu bạn cần ràng buộc thủ công hành vi đặc biệt là một lựa chọn tốt hơn. Với liên kết thủ công, bạn có thể lưu vị trí cuộn và đặt lại vị trí sau khi bạn đã thêm các mục.

+0

Điều này dẫn đến một câu hỏi rõ ràng - làm cách nào để xác định vị trí cuộn hiện tại? –

1

Tạo bộ sưu tậpXem. Hãy thử cách này:

private ObservableCollection<int> m_Values; 
    private CollectionView m_View; 

    private void Bind() 
    { 
     m_Values = new ObservableCollection<int>(); 
     m_View = new CollectionView(m_Values); 
     MyListBox.ItemsSource = m_View; 
    } 

    private void MyListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) 
    { 
     Debug.WriteLine(m_View.CurrentItem); 
     Debug.WriteLine(m_View.CurrentPosition); 
    } 
+1

Vui lòng giải thích thêm. Câu trả lời này dường như không giải quyết được vấn đề - nó chỉ báo cáo mục và vị trí hiện tại. Tôi đang gặp vấn đề tương tự, bằng cách sử dụng một ListBox với một ItemsPanel đặt thành một VirtualizingStackPanel. Vấn đề như tôi thấy là các mục trong hộp danh sách tiếp tục di chuyển khi các mục mới được thêm vào bộ sưu tập quan sát được. Mặc dù có thể di chuyển các mục trở lại vị trí của chúng sau khi một mục mới được thêm vào (ví dụ: bằng cách sử dụng SelectedIndex), điều này tạo ra một chuyển động giật. Điều cần thiết là một cách để ngăn vị trí cuộn thay đổi ngay từ đầu khi các mục mới được thêm vào. – CyberMonk

+0

Tôi có cùng một vấn đề, nhưng giải pháp của bạn giả định somethig được chọn. Nhưng nếu người dùng không muốn chọn bất cứ điều gì? Chỉ cần di chuyển một nơi nào đó và rời khỏi nó. – EvAlex

0

Bạn có kiểm soát khi mọi thứ được thêm vào không? Tôi có nghĩa là bạn có một hoặc hai điểm xác định nơi dữ liệu được thay đổi? Nếu vậy, một giải pháp dễ dàng (có lẽ không thanh lịch) sẽ có một biến int cục bộ để giữ ListBox.SelectedIndex hiện tại. Ngay trước khi thay đổi dữ liệu, lưu selectIndex vào biến này và sau khi dữ liệu được thêm vào, thiết lập SelectedIndex của listBox thành giá trị của biến này.

1

Đầu tiên tìm vị trí hiện tại của ListBox.SelectedIndex và sau đó sử dụng ListBox.ScrollIntoView (/ * Current Index * /). Ngay cả khi các mục mới được thêm vào trong danh sách vị trí hiện tại của bạn và xem sẽ giống nhau.

3

Tôi phải đối mặt với cùng một vấn đề và một hạn chế khác: người dùng không chọn mục, nhưng chỉ cuộn. Đó là lý do tại sao phương pháp ScrollIntoView() là vô ích. Đây là giải pháp của tôi.

Trước tiên, tôi tạo ra lớp ScrollPreserver bắt nguồn từ DependencyObject, với tài sản phụ thuộc kèm theo PreserveScroll kiểu bool:

public class ScrollPreserver : DependencyObject 
{ 
    public static readonly DependencyProperty PreserveScrollProperty = 
     DependencyProperty.RegisterAttached("PreserveScroll", 
      typeof(bool), 
      typeof(ScrollPreserver), 
      new PropertyMetadata(new PropertyChangedCallback(OnScrollGroupChanged))); 

    public static bool GetPreserveScroll(DependencyObject invoker) 
    { 
     return (bool)invoker.GetValue(PreserveScrollProperty); 
    } 

    public static void SetPreserveScroll(DependencyObject invoker, bool value) 
    { 
     invoker.SetValue(PreserveScrollProperty, value); 
    } 

    ... 
} 

thay đổi tài sản callback giả định tài sản được thiết lập bởi ScrollViewer. Phương thức gọi lại thêm ScrollViewer này vào từ điển riêng và thêm trình xử lý sự kiện ScrollChanged vào nó:

private static Dictionary<ScrollViewer, bool> scrollViewers_States = 
    new Dictionary<ScrollViewer, bool>(); 

private static void OnScrollGroupChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
{ 
    ScrollViewer scrollViewer = d as ScrollViewer; 
    if (scrollViewer != null && (bool)e.NewValue == true) 
    { 
     if (!scrollViewers_States.ContainsKey(scrollViewer)) 
     { 
      scrollViewer.ScrollChanged += new ScrollChangedEventHandler(scrollViewer_ScrollChanged); 
      scrollViewers_States.Add(scrollViewer, false); 
     } 
    } 
} 

Từ điển này sẽ giữ tham chiếu đến tất cả ScrollViewers trong ứng dụng sử dụng lớp này. Trong trường hợp các mục của tôi được thêm vào đầu bộ sưu tập. Vấn đề là vị trí khung nhìn không thay đổi. Sẽ ổn khi vị trí là 0: yếu tố đầu tiên trong chế độ xem sẽ luôn là mục đầu tiên. Nhưng khi phần tử đầu tiên trong khung nhìn có chỉ mục khác 0 và các mục mới được thêm vào - chỉ mục của phần tử đó tăng lên để nó được cuộn xuống. Vì vậy, giá trị bool cho biết của ScrollViewer dọc bù đắp được không 0. Nếu nó là 0 có không cần phải làm bất cứ điều gì, và nếu nó không phải là 0 nó là cần thiết để duy trì vị thế của mình so với các mục trong khung nhìn:

static void scrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e) 
{ 
    if (scrollViewers_States[sender as ScrollViewer]) 
     (sender as ScrollViewer).ScrollToVerticalOffset(e.VerticalOffset + e.ExtentHeightChange); 

    scrollViewers_States[sender as ScrollViewer] = e.VerticalOffset != 0; 
} 

ExtentHeightChange được sử dụng ở đây để cho biết số lượng các mục được thêm vào. Trong các trường hợp của tôi chỉ được thêm vào đầu bộ sưu tập, vì vậy tất cả những gì tôi cần làm là tăng VerticalOffset của ScrollViewer bằng giá trị này. Và điều cuối cùng: sử dụng. Dưới đây là ví dụ về ListBox:

<Listbox ...> 
    <ListBox.Resourses> 
     <Style TargetType="ScrollViewer"> 
      <Setter Property="local:ScrollPreserver.PreserveScroll" Value="True" /> 
     </Style> 
    </ListBox.Resourses> 
</ListBox> 

Ta-da!Hoạt động tốt đẹp :)

+0

Không phải bộ nhớ bị rò rỉ do từ điển trong trường tĩnh? – TcKs

+0

DependencyProperties là tất cả tĩnh. Bạn có thể đọc về nó ở đây: http://stackoverflow.com/questions/2989431/why-are-dependency-properties-static – EvAlex

+0

Tôi biết. Nhưng trường "scrollViewers_States" không phải là lối tắt cho thuộc tính phụ thuộc. Nó lưu trữ các trường hợp của ScrollViewer. Bạn có một số mã mà loại bỏ trường hợp cũ từ từ điển? – TcKs

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