Silverlight 3 - ListBox:如何实现平滑滚动并捕获MouseDown/MouseUp事件

6

我试图调整ListBox的行为以适应我的需求,但遇到了几个问题:

1)如何通过编程方式设置ListBox的滚动位置?
ListBox没有提供访问其内部ScrollViewer的接口,因此无法将其滚动到任何您想要的位置。

2)如何准确地设置垂直滚动(即如何实现平滑滚动)?
默认情况下,除了一次滚动一个完整元素(ListBox始终确保第一个元素完全显示),没有其他方法可以滚动列表。

这种行为在大多数情况下都可以,但不适用于我的情况:我需要平滑的移动...

WPF有解决这个问题的方法,但Silverlight没有(请参见问题"is-it-possible-to-implement-smooth-scroll-in-a-wpf-listview")。

3)如何捕获MouseDown和MouseUp事件:
如果对ListBox进行子类化,可能能够捕获MouseUp和MouseMove事件。但是,MouseUp事件从未触发(我怀疑它被ListBox的子元素吞噬了)。

1个回答

8
我已经找到了答案,所以我会回答自己。

1)如何使ListBox平滑滚动:
这个问题在SilverLight 2中没有出现,在SilverLight 3中引入了VirtualizedStackPanel,只有在使用VirtualizedStackPanel时才会发生。
VirtualizedStackPanel在处理大型列表时能够实现更快的刷新(因为只会绘制可见元素)。

对于这个问题有一个解决方法(请注意,不应在大型列表上使用):重新定义ListBox的ItemPanelTemplate,使其使用StackPanel:

<navigation:Page.Resources>
    <ItemsPanelTemplate x:Key="ItemsPanelTemplate">
        <StackPanel/>
    </ItemsPanelTemplate>
</navigation:Page.Resources>

<StackPanel Orientation="Vertical"  x:Name="LayoutRoot">                       
        <ListBox x:Name="list" ItemsPanel="{StaticResource ItemsPanelTemplate}">
        </ListBox>
</StackPanel>

2)如何通过编程方式更改滚动位置
请查看下面的ListBox子类:它提供了对ListBox内部ScrollViewer的访问器


3)如何在listbox中捕获MouseDown / Move / Up事件:

创建一个ListBox的子类,如下所示。三个方法:

 internal void MyOnMouseLeftButtonDown(MouseButtonEventArgs e)  
 protected override void OnMouseMove(MouseEventArgs e)  
 protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)  

这些元素将会被调用,你可以随心所欲地处理它们。有一个微妙的技巧,即 ListBox 的 OnMouseLeftButtonDown 方法永远不会被调用:你需要实现 ListBoxItem 的子类,在这个子类中处理这个事件。

using System;
using System.Collections.Generic;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace MyControls
{
  //In order for this class to be usable as a control, you need to create a folder
  //named "generic" in your project, and a "generic.xaml" file in this folder
  //(this is where you can edit the default look of your controls)
  //
  /*
   * Typical content of an "empty" generic.xaml file : 
    <ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:VideoControls">
    </ResourceDictionary>
   */
  public class MyListBox : ListBox
  {
    public MyListBox()
    {
        DefaultStyleKey = typeof(ListBox);
    }

    public override void OnApplyTemplate()
    {
      base.OnApplyTemplate();
    }

    #region ScrollViewer / unlocking access related code
    private ScrollViewer _scrollHost;
    public ScrollViewer ScrollViewer
    {
      get 
      {
        if (_scrollHost == null)
          _scrollHost = FindVisualChildOfType<ScrollViewer>(this);
        return _scrollHost; 
      }
    }

    public static childItemType FindVisualChildOfType<childItemType>(DependencyObject obj)
      where childItemType : DependencyObject
    {
      // Search immediate children first (breadth-first)
      for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
      {
        DependencyObject child = VisualTreeHelper.GetChild(obj, i);

        if (child != null && child is childItemType)
          return (childItemType)child;

        else
        {
          childItemType childOfChild = FindVisualChildOfType<childItemType>(child);

          if (childOfChild != null)
            return childOfChild;
        }
      }

      return null;
    }
    #endregion

    //Modify MyListBox so that it uses MyListBoxItem instead of ListBoxItem
    protected override DependencyObject GetContainerForItemOverride()
    {
      MyListBoxItem item = new MyListBoxItem(this);
      if (base.ItemContainerStyle != null)
      {
        item.Style = base.ItemContainerStyle;
      }

      return item;
    }

    //OnMouseLeftButtonUp is never reached, since it is eaten by the Items in the list...
    /*
    protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
    {
      base.OnMouseLeftButtonDown(e);
      e.Handled = false;
    }
    */

    internal void MyOnMouseLeftButtonDown(MouseButtonEventArgs e)
    {
    }

    protected override void OnMouseMove(MouseEventArgs e)
    {
      base.OnMouseMove(e);
    }

    protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
    {
      base.OnMouseLeftButtonUp(e);
    }


  }






  public class MyListBoxItem : ListBoxItem
  {
    MyListBox _customListBoxContainer;

    public MyListBoxItem()
    { }

    public MyListBoxItem(MyListBox customListBox)
    {
      this._customListBoxContainer = customListBox;
    }

    protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
    {
      base.OnMouseLeftButtonDown(e);

      if (this._customListBoxContainer != null)
      {
        this._customListBoxContainer.MyOnMouseLeftButtonDown(e);
      }

    }
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接