In the upcoming Silverlight 4 release, mousewheel support for controls will be implemented out of the box. However Silverlight 3 still requires you to roll your own mouse wheel support.
The following MouseWheelProps class provides generic mousewheel support for all Silverlight controls that support the IScrollProvider interface (ScrollViewer, ListBox, DataGrid) or the IRangeValueProvider interface (Slider). This class implements a single attached property called Enable that can be added directly to a control, or as a style for a control.
Step1: Add the following MouseWheelProps class to your Silverlight project:
using System;
using System.Windows;
using System.Windows.Automation.Peers;
using System.Windows.Automation.Provider;
using System.Windows.Controls;
using System.Windows.Input;
namespace SilverlightApplication
{
public static class MouseWheelProps
{
// The Enabled attached property
public static readonly DependencyProperty EnabledProperty =
DependencyProperty.RegisterAttached("Enabled", typeof(bool), typeof(MouseWheelProps),
new PropertyMetadata(false, OnEnabledPropertyChanged));
public static bool GetEnabled(FrameworkElement element)
{
return (bool)element.GetValue(EnabledProperty);
}
public static void SetEnabled(FrameworkElement element, bool value)
{
element.SetValue(EnabledProperty, value);
}
private static void OnEnabledPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
UIElement element = sender as UIElement;
if (element == null)
return;
bool enabled = (bool)e.NewValue;
if (enabled)
element.MouseWheel += OnMouseWheel;
else
element.MouseWheel -= OnMouseWheel;
}
private static void OnMouseWheel(object sender, MouseWheelEventArgs e)
{
if (e.Handled)
return;
UIElement element = sender as UIElement;
if (element == null)
return;
AutomationPeer peer = FrameworkElementAutomationPeer.FromElement(element);
if (peer == null)
peer = FrameworkElementAutomationPeer.CreatePeerForElement(element);
if (peer == null)
return;
// try to get the scroll provider or the range provider
IScrollProvider m_ScrollProvider = peer.GetPattern(PatternInterface.Scroll) as IScrollProvider;
IRangeValueProvider m_RangeValueProvider = null;
if ((element is Control) && (element as Control).HasFocus())
m_RangeValueProvider = peer.GetPattern(PatternInterface.RangeValue) as IRangeValueProvider;
if (m_ScrollProvider == null && m_RangeValueProvider == null)
return;
// set scroll amount
const double kMultiplier = 5.0; // x times the default
const double kFactor = kMultiplier / (30 * 120);
double delta = e.Delta;
delta *= kFactor;
int direction = Math.Sign(delta);
bool shiftKey = (Keyboard.Modifiers & ModifierKeys.Shift) != 0;
bool controlKey = (Keyboard.Modifiers & ModifierKeys.Control) != 0;
if (m_ScrollProvider != null)
{
e.Handled = true;
#if true
if (m_ScrollProvider.VerticallyScrollable && !controlKey)
{
double percent = m_ScrollProvider.VerticalScrollPercent - (delta * m_ScrollProvider.VerticalViewSize);
if (percent < 0) percent = 0;
if (percent > 100) percent = 100;
m_ScrollProvider.SetScrollPercent(m_ScrollProvider.HorizontalScrollPercent, percent);
}
else
if (m_ScrollProvider.HorizontallyScrollable && controlKey)
{
double percent = m_ScrollProvider.HorizontalScrollPercent - (delta * m_ScrollProvider.HorizontalViewSize);
if (percent < 0) percent = 0;
if (percent > 100) percent = 100;
m_ScrollProvider.SetScrollPercent(percent, m_ScrollProvider.VerticalScrollPercent);
}
#else
ScrollAmount scrollAmount = (direction < 0) ? ScrollAmount.SmallIncrement : ScrollAmount.SmallDecrement;
if (m_ScrollProvider.VerticallyScrollable && !controlKey)
m_ScrollProvider.Scroll(ScrollAmount.NoAmount, scrollAmount);
else
if (m_ScrollProvider.HorizontallyScrollable && controlKey)
m_ScrollProvider.Scroll(scrollAmount, ScrollAmount.NoAmount);
#endif
}
if (m_RangeValueProvider != null)
{
e.Handled = true;
double newValue = m_RangeValueProvider.Value + (direction < 0 ? -m_RangeValueProvider.LargeChange : m_RangeValueProvider.LargeChange);
if (newValue >= m_RangeValueProvider.Minimum && newValue <= m_RangeValueProvider.Maximum)
m_RangeValueProvider.SetValue(newValue);
}
}
}
}
Step 2: Add the attached property c:MouseWheelProps.Enabled="True" either directly to a control, or as a Style that can be referenced by a control.
Added directly to a control:
<UserControl x:Class="SilverlightApplication.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:app="clr-namespace:SilverlightApplication"
xmlns:DataGrid="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
>
<Grid>
<DataGrid:DataGrid c:MouseWheelProps.Enabled="True" />
</Grid>
</UserContro>
Added as a Style:
<UserControl x:Class="SilverlightApplication.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:app="clr-namespace:SilverlightApplication"
xmlns:DataGrid="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
>
<Grid>
<Grid.Resources>
<Style x:Key="CommonDataGrid" TargetType="DataGrid:DataGrid">
<Setter Property="c:MouseWheelProps.Enabled" Value="True" />
</Style>
</Grid.Resources>
<DataGrid:DataGrid Style="{StaticResource CommonDataGrid}" />
</Grid>
</UserContro>
That's all there is to it!