Rendere intelligente il deferred scrolling di WPF

di Cristian Civera, in Windows Presentation Foundation,

Nel .NET Framework 3.5 SP1 è presente una nuova funzionalità, volta ad ottimizzare lo scrolling delle liste, che si attiva con la proprietà ScrollViewer.IsDeferredScrolling. Impostandola a true quando si sposta la scrollbar con il mouse non si ottiene l'immediato scrolling fino a quando non si rilascia il pulsante del mouse, evitando di caricare tutti gli elementi sfogliati.

In questo script si propone, sfruttando la tecnica degli attached behavior vista nello script #66, un modo per rendere intelligente questa funzionalità in base a quanti elementi l'ItemsControl destinatario contiene. Si definisce quindi un attached property per specificare quanti elementi massimi sono consentiti per non attivare il deferred scrolling:

public static readonly DependencyProperty AutoDeferredScrollingProperty = DependencyProperty.RegisterAttached("AutoDeferredScrolling", typeof(Int32?), typeof(ScrollViewerEx), new PropertyMetadata(null, new PropertyChangedCallback(OnAutoDeferredLoadingChanged)));

public static void SetAutoDeferredScrolling(DependencyObject d, Int32? value)
{
    d.SetValue(AutoDeferredScrollingProperty, value);
}

public static Int32? GetAutoDeferredScrolling(DependencyObject d)
{
    return (Int32?)d.GetValue(AutoDeferredScrollingProperty);
}

Sul cambio della proprietà AutoDeferredScrolling non resta far altro che valutare quanti elementi ci sono nella lista e impostare l'attached property IsDeferredScrolling. Si intercetta inoltre l'evento ItemsChanged così da rivalutare la condizione quando la sorgente dati cambia:

private static void OnAutoDeferredLoadingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    ItemsControl itemsControl = d as ItemsControl;
    if (itemsControl == null) return;

    // Se cambia la sorgente dati, rivaluto se applicare la proprietà
    itemsControl.ItemContainerGenerator.ItemsChanged += delegate(object sender, System.Windows.Controls.Primitives.ItemsChangedEventArgs ex)
    {
        SetDeferredScrolling(itemsControl, (Int32?)e.NewValue);
    };

    SetDeferredScrolling(itemsControl, (Int32?)e.NewValue);
}

private static void SetDeferredScrolling(ItemsControl itemsControl, Int32? max)
{
    bool enabled = false;
    if (max.HasValue)
        enabled = (itemsControl.Items.Count > max);

    ScrollViewer.SetIsDeferredScrollingEnabled(itemsControl, enabled);
}

L'utilizzo poi è molto banale poiché basta specificare qual'è il limite massimo di elementi prima che si attivi il deferred loading.

<ListBox ItemsSource="{Binding}"
          c:ScrollViewerEx.AutoDeferredScrolling="120">
</ListBox>

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Approfondimenti

I più letti di oggi