Silverlight 3 - ListBox: come raggiungere scorrimento regolare e catturare gli eventi MouseDown / MouseUp

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

Domanda

Sto cercando di adattare il comportamento della ListBox per le mie esigenze e mi sono imbattuto in una serie di problemi

1) Come si può impostare programatically la posizione di scorrimento del ListBox
Il ListBox non fornisce una funzione di accesso alla sua ScrollViewer interno in modo che non è possibile scorrere a dove si vuole.

2) Come impostare con precisione lo scorrimento verticale (cioè come avere uno scorrimento uniforme)?
Per impostazione predefinita, non c'è modo per scorrere l'elenco altra scorrendo un elemento completo alla volta (la casella di riepilogo sarà sempre fare in modo che il primo elemento è mostrato del tutto)

Questo comportamento è ok nella maggior parte dei casi, ma non la mia: voglio un movimento fluido ...),

C'è una soluzione a questo problema con WPF, ma non con Silverlight (vedere la domanda " è-da-possibile da implementare-smooth-scroll-in-a-WPF-listview ").

3) Come catturare gli eventi MouseDown e MouseUp:
Se si sottoclasse ListBox, si potrebbe essere in grado di catturare gli eventi MouseUp e MouseMove. Tuttavia l'evento MouseUp viene mai sparato (ho il sospetto che è stato mangiato da sottoelementi ListBox)

È stato utile?

Soluzione

Ho trovato la risposta, così risponderò io stesso.


1) Come rendere il rotolo ListBox senza intoppi:
Questo problema non è accaduto in Silverlight 2, e succede solo con Silverlight 3, in cui è stato introdotto il VirtualizedStackPanel.
Il VirtualizedStackPanel permette molto più veloce di aggiornamento nel caso di liste enormi (come solo gli elementi visibili sono disegnati)

C'è una soluzione per questo (attenzione, non deve essere utilizzato su enormi liste): si ridefinisce ItemPanelTemplate del ListBox, in modo che utilizzi 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) Come modificare la posizione di scorrimento programatically
Vedere la sottoclasse di ListBox sotto: fornisce una funzione di accesso alla ScrollViewer interna del ListBox


3) Come catturare i MouseDown / Sposta / Up eventi nella casella di riepilogo:

Create una sottoclasse di ListBox come illustrato di seguito. I 3 metodi:

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

si chiamerà e si può fare quello che vuoi con loro. C'è un sottile trucco che è che il metodo di OnMouseLeftButtonDown ListBox non viene mai chiamato:. È necessario implementare una sottoclasse di ListBoxItem in cui è possibile gestire questo 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);
      }

    }
  }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top