Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Silverlight : Enable Mouse Wheel on Slider with Behaviors

0.00/5 (No votes)
7 Jul 2010 1  
Custom Behaviors to enable MouseWheel support to Silverlight Slider and bit more

You might need to unblock some DLLs in:

  • MouseWheelApp\MouseWheelApp\Bin\Debug
  • MouseWheelApp\MouseWheelBehaviorLibrary\Bin\Debug

Live App
Kudos to Adefwebserver for hosting my app

Introduction

This article will walk through the creation of 2 simple behaviors to enable MouseWheel support for the Slider which Silverlight lacks as of this moment. This will also be a simple introduction to behaviors.

The Problem

The Silverlight Slider control does not have MouseWheel support. There is an event MouseWheel that you can listen to, but it will not expose the Delta value which tells whether the wheel was scrolled up or down in Blend. One way to add mouse support to your Slider is by using code behind which will not give designers freedom or be as reusable compared to a behavior.

Tried using ChangePropertyAction, but there is no way to get Mouse Values. This limits designers' ability to do their jobs.

My Solution

I have made 2 different behaviors that will enable MouseWheel support and these behaviors use properties set on the Slider for some flexibility. The properties are: Maximum, Minimum, SmallChange, and Value. The purpose is to allow designers to set boundaries, and how much the value should increment when mouse wheel is scrolled.

Beyond the Slider

While this is a behavior for the Slider control, this can be used for more. Because the slider contains properties to set Maximum, Minimum, and SmallChange, this is perfect for binding your properties to and setting up boundaries. This was originally designed for allowing MouseWheel support to whatever it associates (that has numeric property and boundaries) so it can be used for setting up other controls with MouseWheel though some bindings are required. It also avoids code behind by the use of behaviors. For example, a volume control on a video player where you can bind the value of the volume to Slider's value, and you associate my behavior to the video player so a user can adjust volume by MouseWheel when mouse is above the player. Or maybe resize an image or window by MouseWheel and hide the slider.

Basic Sample

Before I go dig into the code, I would like to give an overview of what it can do so you can decide whether you would like to go on further.

In this app which we will be creating in the course of the article, we have a rectangle, and 3 sliders. Each of them has a simple behavior that is attached to the slider to enable mouseWheel support. In addition to this, I have another Behavior that is attached to the Rectangle which will respond to mouseWheel events when the mouse is on the Rectangle. This behavior will change one of the Slider's value.

The Code

Start by creating a new Silverlight application and name it something like MouseWheelApp, this will be the app that will use the behaviors. Go ahead and select Host the Silverlight Application in a new website.

Now add a new project and select Silverlight Class Library and name it MouseWheelBehaviorLibrary.

To the MouseWheelBehaviorLibrary, add a reference to System.Windows.Interactivity. This DLL is from Microsoft Expression Blend SDK.

In the MouseWheelBehaviorLibrary project, add a new class and name it EnableSliderMouseWheel.

EnableSliderMouseWheel.cs

  1. Add using statement:
    using System.Windows.Interactivity;
  2. Inherit class from:
    public class EnableSliderMouseWheel : Behavior<Slider>

    The class is inheriting from the Behavior and setting the generic to a Slider control. By setting the type to a Slider, it will restrict what this behavior can attach to. For this behavior, I would like to make a simple one that just enables MouseWheel support on attach, or for the designer drop on to it.

  3. Now paste the following code:
    protected override void OnAttached()
            {
                base.OnAttached();
    
                //attach event handler on mouse wheel event
                AssociatedObject.MouseWheel += 
            new MouseWheelEventHandler(SliderMouseScroll_MouseWheel);
            }

    This code runs when the behavior is "attached" to the control. AssociatedObject represents what it is attached to, in our case a Slider control. We are adding an event handler to the MouseWheel Event. (Code will error at this point, I will show the SliderMouseScroll_MouseWheel method later.) Basically what is happening is once the behavior attaches to the slider, it is adding the event handler to manipulate the slider values.

  4. Paste the following code again:
    protected override void OnDetaching()
    {
          base.OnDetaching();
    
          //remove event handler on mouse wheel event
          AssociatedObject.MouseWheel -= 
            new MouseWheelEventHandler(SliderMouseScroll_MouseWheel);
    }

    This is the opposite of the code above, when this is detached it will remove the event handler that it attached.

  5. Now paste the meat of the behavior, the method that gets fired when Mouse is scrolled.
        void SliderMouseScroll_MouseWheel(object sender, MouseWheelEventArgs e)
            {
                //Delta = how much the wheel was scrolled. + for up - for down
    
                //check to see if Delta is positive.
                if (e.Delta > 0)
                {
                    //using small change of Target(slider) property. 
                    //this allows how much value can change from the designer
                    //
                    //alternatively you can actually use the delta value instead
                    //of forcing small change increments.
    
                    AssociatedObject.Value = AssociatedObject.Value + 
    					AssociatedObject.SmallChange;
                }
                else //same as above just backwards
                {
                    //using small change of Target(slider) property. 
                    //this allows how much value can change from the designer
                    //
                    //alternatively you can actually use the delta value instead
                    //of forcing small change increments.
    
                    AssociatedObject.Value = AssociatedObject.Value - 
    					AssociatedObject.SmallChange;
                }
            }    

First I check for the Delta value, this tells how much the mouse was scrolled and direction. If it's positive it was scrolled up, and negative if it was scrolled down. I only use the Delta to check the direction. Next I get the value of the slider and add or subtract the slider's SmallChange value. By using the SmallChange, I allow designers to set how much it should change.

I do not have any checks to see if it will go over or less than the boundaries, this is because it already has these checks built in.

Our First Behavior is complete. Now we will start making the example shown above.

App to Use the Behavior

The next step is to set up an app that will consume this behavior.

  1. Add reference to the DLL from the previous step or MouseWheelBehaviorLibrary. Just go to the bin directory of the MouseWheelBehaviorLibrary project and select MouseWheelBehaviorLibrary.dll.
  2. Open the MainPage.xaml from the MouseWheelApp in Blend. (right click and select Open in Expression Blend)

    Make sure we have the Behavior.

  3. Re-create a UI similar to this (Rectangle, 3 sliders, textblock as labels). Make sure the values of rectangle's value are not set to Auto, which will not allow binding in the next step. The sliders and labels is in a grid.

  4. Bind the Slider Values to the Rectangle Properties. Make sure that its two-way binding. Next Set the Maximum, Minimum and SmallChange to what suits your project. Note Opacity Maximum should be 1.

  5. Attach the Behavior we have created to the Sliders and run. Now when you scroll your mouse on top of the Slider, it will change the value. (Just drag and drop the behavior on to the Sliders.)

The More Flexible Behavior

The next one takes it a step further. This one will be able to attach to any control and will respond to MouseWheel when the mouse is on the attached control. As explained earlier, this can be used to add MouseWheel support to other controls. (Because it's almost identical, I will breeze through some details explained in the previous one.)

  1. Like the previous behavior, we will need a new class in our library. Add a new class called EnableMouseWheel.cs. Add using:
    using System.Windows.Interactivity;
  2. Inherit from TargetedTriggerAction<slider><T>, use Slider for T. Also Implement the Invoke method or copy the method.
    public class EnableMouseWheel : TargetedTriggerAction<Slider>
        {
            //this method is required for the base class
            protected override void Invoke(object parameter)
            {
    
            }
        }

    The Invoke method here we will do nothing with. This type of behavior will attach to anything, and the generic <T> is where you can specify a target class. The Target is used for accessing another control. For ours, we will set it to Slider so when MouseWheel was scrolled, the Behavior will change the value of the Target 'Slider'.

  3. Copy the following code:
            protected override void OnAttached()
            {
                base.OnAttached();
    
                //add event handler to mouse wheel event
                ((FrameworkElement)AssociatedObject).MouseWheel += 
    		new MouseWheelEventHandler(SliderMouseScroll_MouseWheel);
            }
    
            protected override void OnDetaching()
            {
                base.OnDetaching();
    
                //remove the event handler
                ((FrameworkElement)AssociatedObject).MouseWheel -= 
    		new MouseWheelEventHandler(SliderMouseScroll_MouseWheel);
            }
    
            //this method runs on Mouse Wheel event
            void SliderMouseScroll_MouseWheel(object sender, MouseWheelEventArgs e)
            {
                //Delta = how much the wheel was scrolled. + for up - for down
    
                //check to see if Delta is positive.
                if (e.Delta > 0)
                {
                    //using small change of Target(slider) property. 
                    //this allows how much value can change from the designer
                    //
                    //alternatively you can actually use the delta value instead
                    //of forcing small change increments.
    
                    Target.Value = Target.Value + Target.SmallChange;
                }
                else //same as above just backwards
                {
                    //using small change of Target(slider) property. 
                    //this allows how much value can change from the designer
                    //
                    //alternatively you can actually use the delta value instead
                    //of forcing small change increments.
    
                    Target.Value = Target.Value - Target.SmallChange;
                }
            }

    This is basically the same code, but with a few changes. When we attach, we will cast it to a FrameworkElement which is the base for all controls. We need to cast it because it doesn't know what type it really is. Next is in the event handler where we are using a Target instead of AssociatedObject, this is because we want to edit the Slider's value which is the Target instead of what we attached to (AssociatedObject).

  4. This is an optional step. If we look at the screenshot when we checked to see if we had the Behavior, you might have noticed there was no explanation of what the behavior is. Here we will add that:
     [System.ComponentModel.Description("Target : Trigger. 
    	Responds to mousewheel event of attached object when focused. 
    	Manipulates slider values based on slider properties.")]
        public class EnableMouseWheel : TargetedTriggerAction<Slider>
        {

    Add the attribute. Build and go back to the Mainpage.xaml in Blend.

Using the Behavior

  1. Check to see that we have the Behavior and the description:

  2. Attach the Behavior to the Rectangle and in the properties of the Behavior, set the Target to one of the sliders.

  3. Now Run and when you scroll on the Rectangle, it should change the slider. Now you are done.

Full Code

using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

using System.Windows.Interactivity;

namespace MouseWheelBehaviorLibrary
{
    [System.ComponentModel.Description
	("Target : Trigger. Responds to mousewheel event of attached object 
	when focused. Manipulates slider values based on slider properties.")]
    public class EnableMouseWheel : TargetedTriggerAction<Slider>
    {
        //this method is required for the base class
        protected override void Invoke(object parameter)
        {

        }

        protected override void OnAttached()
        {
            base.OnAttached();

            //add event handler to mouse wheel event
            ((FrameworkElement)AssociatedObject).MouseWheel += 
		new MouseWheelEventHandler(SliderMouseScroll_MouseWheel);
        }

        protected override void OnDetaching()
        {
            base.OnDetaching();

            //remove the event handler
            ((FrameworkElement)AssociatedObject).MouseWheel -= 
		new MouseWheelEventHandler(SliderMouseScroll_MouseWheel);
        }

        //this method runs on Mouse Wheel event
        void SliderMouseScroll_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            //Delta = how much the wheel was scrolled. + for up - for down

            //check to see if Delta is positive.
            if (e.Delta > 0)
            {
                //using small change of Target(slider) property. 
                //this allows how much value can change from the designer
                //
                //alternatively you can actually use the delta value instead
                //of forcing small change increments.

                Target.Value = Target.Value + Target.SmallChange;
            }
            else //same as above just backwards
            {
                //using small change of Target(slider) property. 
                //this allows how much value can change from the designer
                //
                //alternatively you can actually use the delta value instead
                //of forcing small change increments.

                Target.Value = Target.Value - Target.SmallChange;
            }
        }
    }
}

/////
/////
/////

using System.Windows.Controls;
using System.Windows.Input;

using System.Windows.Interactivity;

namespace MouseWheelBehaviorLibrary
{
    public class EnableSliderMouseWheel : Behavior<Slider>
    {
        protected override void OnAttached()
        {
            base.OnAttached();

            //attach event handler on mouse wheel event
            AssociatedObject.MouseWheel += new MouseWheelEventHandler
			(SliderMouseScroll_MouseWheel);
        }

        protected override void OnDetaching()
        {
            base.OnDetaching();

            //remove event handler on mouse wheel event
            AssociatedObject.MouseWheel -= new MouseWheelEventHandler
			(SliderMouseScroll_MouseWheel);
        }

        void SliderMouseScroll_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            //Delta = how much the wheel was scrolled. + for up - for down

            //check to see if Delta is positive.
            if (e.Delta > 0)
            {
                //using small change of Target(slider) property. 
                //this allows how much value can change from the designer
                //
                //alternatively you can actually use the delta value instead
                //of forcing small change increments.

                AssociatedObject.Value = AssociatedObject.Value + 
				AssociatedObject.SmallChange;
            }
            else //same as above just backwards
            {
                //using small change of Target(slider) property. 
                //this allows how much value can change from the designer
                //
                //alternatively you can actually use the delta value instead
                //of forcing small change increments.

                AssociatedObject.Value = AssociatedObject.Value - 
					AssociatedObject.SmallChange;
            }
        }
    }
}

Notes

There are some compatibilty issues I have found with the EnableMouseWheel Behavior which are primarily around controls that already have some MouseWheel support. Combobox seems to work only if selected index is -1 and things like the listbox seem to work once it has reached the end of the list.

For more information on Behaviors, please see Silverlight Show.

Thanks for reading and I hope this was somewhat useful for you. This is my first article, so I would appreciate any feedback on the article or the code. This is my first article on CodeProject.

History

  • 7th July, 2010: Initial post

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here