
InertiaListBox – ListBox com inercia!!!
Março 13, 2009Com o InertiaScrollViewer que podem encontrar mais abaixo tinhamos um problema ao usa-lo numa ListBox devido aos eventos do Selector, para isso resolvi criar esta classe que nos permite ter o mesmo comportamento mas agora com uma ListBox.
Portanto, cá esta o código do .cs
[TemplatePart(Name = "PART_Scroll", Type = typeof(InertiaScrollViewer))]
public class InertiaListBox : ListBox
{
#region Declara-se que
private SelectionChangedEventArgs _selectionChangedEventArgs;
private Point _offset;
private Point _mouseDown;
List<object> _oldSelecteds;
#endregion
static InertiaListBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(InertiaListBox), new FrameworkPropertyMetadata(typeof(InertiaListBox)));
}
public InertiaListBox()
{
_offset = new Point(0.0, 0.0);
_selectionChangedEventArgs = null;
_oldSelecteds = new List<object>();
this.PreviewMouseDown += new MouseButtonEventHandler(InertiaListBox_PreviewMouseDown);
Style _styleItems = new Style(typeof(ListBoxItem));
TemplateBindingExtension b=new TemplateBindingExtension(InertiaListBox.IsSelectedProperty);
_styleItems.Setters.Add(new Setter(Selector.IsSelectedProperty,b));
}
#region Eventos
void InertiaListBox_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
_offset = new Point((this.Template.FindName("PART_Scroll", this) as InertiaScrollViewer).HorizontalOffset,
(this.Template.FindName("PART_Scroll", this) as InertiaScrollViewer).VerticalOffset);
_mouseDown = new Point(Mouse.GetPosition(this).X + _offset.X,
Mouse.GetPosition(this).Y + _offset.Y);
}
#endregion
#region Auxiliar
private void SetIsSelected(SelectionChangedEventArgs e)
{
foreach (var item in _oldSelecteds)
{
InertiaListBox.SetIsSelected(this.ItemContainerGenerator.ContainerFromItem(item), false);
}
_oldSelecteds = new List<object>();
if (e != null)
{
foreach (var item in e.AddedItems)
{
_oldSelecteds.Add(item);
InertiaListBox.SetIsSelected(this.ItemContainerGenerator.ContainerFromItem(item), true);
}
}
}
#endregion
#region Overrides
protected override void OnPreviewMouseUp(MouseButtonEventArgs e)
{
Point _mouseUp = new Point(Mouse.GetPosition(this).X + _offset.X,
Mouse.GetPosition(this).Y + _offset.Y);
if (_selectionChangedEventArgs != null)
{
switch (Orientation)
{
case Orientation.Horizontal:
if (Math.Abs(_mouseUp.X - _mouseDown.X) < 2)
{
SetIsSelected(_selectionChangedEventArgs);
base.OnSelectionChanged(_selectionChangedEventArgs);
_selectionChangedEventArgs = null;
}
break;
case Orientation.Vertical:
if (Math.Abs(_mouseUp.Y - _mouseDown.Y) < 2)
{
SetIsSelected(_selectionChangedEventArgs);
base.OnSelectionChanged(_selectionChangedEventArgs);
_selectionChangedEventArgs = null;
}
break;
default:
break;
}
}
base.OnMouseUp(e);
}
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
{
_selectionChangedEventArgs = e;
}
#endregion
#region Properties
public static new bool GetIsSelected(DependencyObject obj)
{
return (bool)obj.GetValue(IsSelectedProperty);
}
public static new void SetIsSelected(DependencyObject obj, bool value)
{
obj.SetValue(IsSelectedProperty, value);
}
// Using a DependencyProperty as the backing store for IsSelected. This enables animation, styling, binding, etc...
public static new readonly DependencyProperty IsSelectedProperty =
DependencyProperty.RegisterAttached("IsSelected", typeof(bool), typeof(InertiaListBox), new UIPropertyMetadata(false));
public Orientation Orientation
{
get { return (Orientation)GetValue(OrientationProperty); }
set { SetValue(OrientationProperty, value); }
}
// Using a DependencyProperty as the backing store for Orientation. This enables animation, styling, binding, etc...
public static readonly DependencyProperty OrientationProperty =
DependencyProperty.Register("Orientation", typeof(Orientation), typeof(InertiaListBox), new UIPropertyMetadata(Orientation.Vertical));
#endregion
}
O template onde usamos o InertiaSrollviewer
<Style TargetType="{x:Type local:InertiaListBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:InertiaListBox}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<local:InertiaScrollViewer Focusable="False" x:Name="PART_Scroll">
<StackPanel Orientation="{TemplateBinding Orientation}" IsItemsHost="True" />
</local:InertiaScrollViewer>
</Border>
</ControlTemplate
</Setter.Value>
</Setter>
</Style>
A partir de agora e sempre que quisermos usa-la, basta definir o ItemTemplate ou o Style para ListBoxItem, por exemplo
<local:InertiaListBox Orientation="Vertical">
<local:InertiaListBox.Resources>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<TextBlock x:Name="mov" Text="{Binding .}"/>
<ControlTemplate.Triggers>
<Trigger Property="local:InertiaListBox.IsSelected" Value="True">
<Setter Property="Background" TargetName="mov" Value="Blue"/>
<Setter Property="Foreground" TargetName="mov" Value="White"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
</Style.Triggers>
</Style>
</local:InertiaListBox.Resources>
</local:InertiaListBox>
Para já é tudo, confiram os updates ao InertiaScrollViewer ![]()
Até breve,
Miguel Duarte