Silverlight 3 - Список файлов :как добиться плавной прокрутки и перехватывать события MouseDown / MouseUp

StackOverflow https://stackoverflow.com/questions/1354708

Вопрос

Я пытаюсь адаптировать поведение ListBox к своим потребностям и столкнулся с несколькими проблемами

1) Как вы можете программно установить положение прокрутки списка
ListBox не предоставляет средства доступа к своему внутреннему ScrollViewer, так что вы не можете прокрутить его туда, куда хотите.

2) Как точно настроить вертикальную прокрутку (т. е. как добиться плавной прокрутки)?
По умолчанию нет другого способа прокручивать список, прокручивая по одному полному элементу за раз (Listbox всегда будет следить за тем, чтобы первый элемент отображался полностью)

Такое поведение нормально в большинстве случаев, но не мое :Я хочу плавного движения...),

Существует решение этой проблемы с помощью WPF, но не с помощью Silverlight (см. Вопрос "возможно ли реализовать плавную прокрутку в wpf-listview" ).

3) Как перехватить события MouseDown и MouseUp :
Если вы создадите подкласс ListBox , возможно, вам удастся перехватить события MouseUp и MouseMove.Однако событие MouseUp никогда не запускается (я подозреваю, что оно поглощается подэлементами ListBox)

Это было полезно?

Решение

Я нашел ответ, так что я отвечу сам.


1) Как сделать так, чтобы поле списка прокручивалось плавно :
Эта проблема не возникала в SilverLight 2, и она возникает только с SilverLight 3, в котором была введена VirtualizedStackPanel.
VirtualizedStackPanel обеспечивает гораздо более быстрое обновление в случае огромных списков (поскольку отображаются только видимые элементы).

Для этого есть обходной путь (будьте осторожны, его не следует использовать в огромных списках) :вы переопределяете ItemPanelTemplate в ListBox, чтобы он использовал 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 ниже :он предоставляет средство доступа к внутреннему средству просмотра списка


3) Как перехватить события наведения курсора мыши / перемещения / Вверх в списке :

Создайте подкласс ListBox, как показано ниже.Эти 3 метода :

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

будут вызваны, и вы сможете делать с ними все, что захотите.Существует один тонкий трюк, который заключается в том, что метод OnMouseLeftButtonDown ListBox никогда не вызывается :вам нужно реализовать подкласс 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);
      }

    }
  }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top