2009-08-30 16 views
6

que estoy tratando de adaptar el comportamiento del cuadro de lista para mis necesidades y me encontré con varios problemasSilverlight 3 - ListBox: cómo lograr desplazamiento suave y atrapar eventos MouseDown/MouseUp

1) ¿Cómo se puede establecer mediante programación la posición de desplazamiento de ListBox
ListBox no proporciona un acceso a su ScrollViewer interno para que no pueda desplazarse a donde desee.

2) Cómo configurar con precisión el desplazamiento vertical (es decir, cómo tener un desplazamiento suave)?
Por defecto, no hay manera de desplazarse por la lista otra desplazándose un elemento completo a la vez (el cuadro de lista siempre se asegurará de que el primer elemento se muestra en su totalidad)

Este comportamiento es aceptable en la mayoría de los casos, pero no mío: quiero un movimiento suave ...),

Existe una solución a este problema con WPF, pero no con Silverlight (vea la pregunta "is-it-possible-to-implement-smooth-scroll-in-a-wpf-listview").

3) Cómo atrapar los eventos MouseDown y MouseUp:
Si subclase el ListBox, es posible que pueda detectar los eventos MouseUp y MouseMove. Sin embargo, el evento MouseUp nunca se activa (sospecho que se está comiendo por los subelementos de ListBox)

Respuesta

8

He encontrado la respuesta, así que me responderé.


1) ¿Cómo hacer el rollo ListBox sin problemas:
Este problema no ocurrió en Silverlight 2, y ocurre solamente con Silverlight 3, en el que se introdujo el VirtualizedStackPanel.
El VirtualizedStackPanel mucho más rápido permite actualizar en el caso de grandes listas (como se dibujan sólo los elementos visibles)

Hay una solución para esto (ten cuidado, que no debe ser utilizado en grandes listas): se redefine del ListBox ItemPanelTemplate, de modo que utilice 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) Cómo cambiar mediante programación la posición de desplazamiento
ver la subclase de cuadro de lista a continuación: proporciona un descriptor de acceso a la ScrollViewer interna del ListBox


3) Cómo coger el MouseDown/Mover/Eventos en el cuadro de lista:

crear una subclase de cuadro de lista como se muestra a continuación. Se llamarán los 3 métodos:

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

y puede hacer lo que quiera con ellos. Hay un truco sutil que es que nunca se llama al método OnMouseLeftButtonDown de ListBox: necesita implementar una subclase de ListBoxItem donde pueda manejar este evento.

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); 
     } 

    } 
    } 
} 
Cuestiones relacionadas