2009-08-30 18 views
6

Staram się przystosować zachowania ListBox dla moich potrzeb i wpadłem na kilka problemówSilverlight 3 - ListBox: jak osiągnąć Smooth Scroll i połowu zdarzenia MouseDown/mouseUp

1) W jaki sposób można programowo określonymi pozycja przewijania ListBox'a
ListBox nie zapewnia akcesora do jego wewnętrznego ScrollViewer, więc nie można go przewijać w dowolne miejsce.

2) Jak dokładnie ustawić pionowe przewijanie (czyli jak uzyskać płynne przewijanie)?
Domyślnie nie ma sposobu, aby przewinąć listę innych przewijając jednego kompletnego elementu naraz (ListBox zawsze upewnić się, że pierwszy element jest pokazany w całości)

Takie zachowanie jest ok, w większości przypadków, ale nie moje: chcę płynnego ruchu ...),

Istnieje rozwiązanie tego problemu z WPF, ale nie z Silverlight (patrz pytanie "is-it-possible-to-implement-smooth-scroll-in-a-wpf-listview").

3) Jak złapać zdarzenia MouseDown i MouseUp:
Jeśli podklasę ListBox, możesz być w stanie złapać zdarzenia MouseUp i MouseMove. Jednak zdarzenie MouseUp nigdy nie jest wyrzucane (podejrzewam, że jest ono zjedzone przez podelementy ListBox)

Odpowiedz

8

Znalazłem odpowiedź, więc odpowiem sobie.


1) Jak zrobić zwój ListBox płynnie:
Ten problem nie stało w Silverlight 2, i zdarza się tylko z Silverlight 3, w którym VirtualizedStackPanel został wprowadzony.
VirtualizedStackPanel umożliwia znacznie szybsze odświeżanie w przypadku ogromnych list (jak tylko widoczne elementy są rysowane)

Istnieje obejście tego (uwaga, to nie powinien być stosowany na ogromnych list): przedefiniować pola listy ItemPanelTemplate, tak że używa 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) Jak programowo zmienić pozycję przewijania
Patrz podklasę ListBox poniżej: dostarcza akcesor do wewnętrznego ScrollViewer z ListBox


3) Jak złapać MouseDown/Move/Up wydarzenia w polu listy:

utworzyć podklasę ListBox, jak pokazano poniżej. Trzy metody:

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

będą wywoływane, a Ty będziesz mógł robić z nimi, co chcesz. Istnieje jedna subtelna sztuczka polegająca na tym, że metoda ListBox OnMouseLeftButtonDown nigdy nie jest wywoływana: należy zaimplementować podklasę obiektu ListBoxItem, w którym można obsłużyć to zdarzenie.

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

    } 
    } 
} 
Powiązane problemy