解决WPF程序中ListBox ItemsSource变化时不重置ScrollBar的问题

当我们改变ListBox的ItemsSource时,会发现这样一个问题:数据源变化时,虽然控件中的内容会跟着变化,但滚动条却不会重置

举个例子:

  1. 将ListBox绑定到一百个字符串: listbox.ItemsSource = Enumerable.Range(0, 100).Select(i => "## " + i);
  2. 将ListBox的滚动条拖到最后,使之能看到最后的"## 99",看不到最开始的"## 0"。
  3. 将ListBox绑定到另外一百个字符串: listbox.ItemsSource = Enumerable.Range(0, 100).Select(i => ">> " + i); 这时我们会发现:虽然数据内容会变更,但滚动条仍然在最后,能看到最后的">> 99",看不到最开始的">> 0"。

大多数情况下,这个并不是我们所期望的结果。如何解决这个问题,stackoverflow文章Reset scrollbar on ItemsSource change给了一个解决方案:找到ListBox的ScrollViewer,响应ListBox的SourceUpdated事件,滚动滚动条到顶端。

listbox.SourceUpdated += (_1, _2) => scrollView.ScrollToTop();

这种方法本身没有什么问题,但是由于ScrollViewer是视觉树的一部分,从ListBox上获取并不容易(可能会修改模板)。我后来又从Wordpress文章ListBox – Automatically scroll CurrentItem into View上找到了一个方案:响应ListBox的Items.CurrentChanged事件,通过函数ScrollIntoView实现滚动到顶端。

    listbox.Items.CurrentChanged += (_1, _2) => listbox.ScrollIntoView(listbox.Items[0]);

原文本来的目的是为了实现将ListBox自动滚动到CurrentItem,也可用来解决这个问题。原文更是实现了一个附加属性,使得可以在XAML中直接使用,来非常方便。

<ListBox local:ListBoxExtenders.AutoScrollToCurrentItem="True"/>

由于众所周知的原因,Wordpress这个并不存在的网站只能从火星上访问,没有火星专线的朋友可以找方校长借,或者直接参考我下面的代码(稍微修改了点,貌似也没有什么bug)。

 

ExpandedBlockStart.gif View Code 
 1      ///   <summary>
 2       ///  This class contains a few useful extenders for the ListBox
 3       ///   </summary>
 4       public  class ListBoxExtenders : DependencyObject
 5     {
 6          #region Properties
 7 
 8          public  static  readonly DependencyProperty AutoScrollToCurrentItemProperty = DependencyProperty.RegisterAttached( " AutoScrollToCurrentItem ",
 9              typeof( bool),  typeof(ListBoxExtenders),  new UIPropertyMetadata( default( bool), OnAutoScrollToCurrentItemChanged));
10 
11          ///   <summary>
12           ///  Returns the value of the AutoScrollToCurrentItemProperty
13           ///   </summary>
14           ///   <param name="obj"> The dependency-object whichs value should be returned </param>
15           ///   <returns> The value of the given property </returns>
16           public  static  bool GetAutoScrollToCurrentItem(DependencyObject obj)
17         {
18              return ( bool)obj.GetValue(AutoScrollToCurrentItemProperty);
19         }
20 
21          ///   <summary>
22           ///  Sets the value of the AutoScrollToCurrentItemProperty
23           ///   </summary>
24           ///   <param name="obj"> The dependency-object whichs value should be set </param>
25           ///   <param name="value"> The value which should be assigned to the AutoScrollToCurrentItemProperty </param>
26           public  static  void SetAutoScrollToCurrentItem(DependencyObject obj,  bool value)
27         {
28             obj.SetValue(AutoScrollToCurrentItemProperty, value);
29         }
30 
31          #endregion
32 
33          #region Events
34 
35          ///   <summary>
36           ///  This method will be called when the AutoScrollToCurrentItem
37           ///  property was changed
38           ///   </summary>
39           ///   <param name="sender"> The sender (the ListBox) </param>
40           ///   <param name="e"> Some additional information </param>
41           public  static  void OnAutoScrollToCurrentItemChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
42         {
43              var listBox = sender  as ListBox;
44              if ((listBox ==  null) || (listBox.Items ==  null))
45                  return;
46 
47              var enable = ( bool)e.NewValue;
48              var autoScrollToCurrentItemWorker =  new EventHandler((_1, _2) => OnAutoScrollToCurrentItem(listBox, listBox.Items.CurrentPosition));
49 
50              if (enable)
51                 listBox.Items.CurrentChanged += autoScrollToCurrentItemWorker;
52              else
53                 listBox.Items.CurrentChanged -= autoScrollToCurrentItemWorker;
54         }
55 
56          ///   <summary>
57           ///  This method will be called when the ListBox should
58           ///  be scrolled to the given index
59           ///   </summary>
60           ///   <param name="listBox"> The ListBox which should be scrolled </param>
61           ///   <param name="index"> The index of the item to which it should be scrolled </param>
62           public  static  void OnAutoScrollToCurrentItem(ListBox listBox,  int index)
63         {
64              if (listBox !=  null && listBox.Items !=  null && listBox.Items.Count > index && index >=  0)
65                 listBox.ScrollIntoView(listBox.Items[index]);
66         }
67 
68          #endregion
69

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值