Implement MouseWheel support for Silverlight 3 controls

by Jim McCurdy 29. January 2010 10:43

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!

Digg It!DZone It!Del.icio.usStumbleUpon

Comments

1/29/2010 12:34:20 PM #

Implement MouseWheel support for Silverlight 3 controls

You've been kicked (a good thing) - Trackback from DotNetKicks.com

DotNetKicks.com

2/1/2010 2:58:16 PM #

Implement MouseWheel support for Silverlight 3 controls

Thank you for submitting this cool story - Trackback from DotNetShoutout

DotNetShoutout

2/4/2010 4:30:58 AM #

Social comments and analytics for this post

This post was mentioned on Twitter by Erwin8: #silverlight - Implement MouseWheel support for Silverlight 3 controls: Tags: silverlight mousewheel tweet Posted ... http://bit.ly/bX9yV7

uberVU - social comments

Add comment




biuquote
Loading



Powered by BlogEngine.NET 1.5.0.7
Theme by Mads Kristensen


My Photo Jim is always looking for new clients in need of software development expertise.  He is particularly well suited for Silverlight, .NET, ASP.NET, and WPF projects.

Professional Biography

Jim McCurdy operates Face to Face Software, where he works designing, developing, and managing software projects for a variety of clients.

Jim currently specializes in development projects for Silverlight, .NET, ASP.NET, and WPF platforms. One such project is a complete web site using Silverlight, .NET, and C#; a unique financial and lifestyle planning web application at YinYangMoney.com.

Jim has worked in the software industry for as long as he can remember, and has broad expertise in Web, Windows, and systems technologies. Jim has been a team player on many agile development projects throughout his career, and is a founding member at software startups Astral Development and Powerhouse Entertainment.

You can Email Jim at Face to Face Software.


Welcome Readers