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
- Add using statement:
using System.Windows.Interactivity;
- 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.
- Now paste the following code:
protected override void OnAttached()
{
base.OnAttached();
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.
- Paste the following code again:
protected override void OnDetaching()
{
base.OnDetaching();
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.
- Now paste the meat of the behavior, the method that gets fired when Mouse is scrolled.
void SliderMouseScroll_MouseWheel(object sender, MouseWheelEventArgs e)
{
if (e.Delta > 0)
{
AssociatedObject.Value = AssociatedObject.Value +
AssociatedObject.SmallChange;
}
else {
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.
- 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
.
- Open the MainPage.xaml from the
MouseWheelApp
in Blend
. (right click and select Open in Expression Blend)
Make sure we have the Behavior
.
- 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.
- 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.
- 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.)
- 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;
- Inherit from
TargetedTriggerAction<slider><T>
, use Slider
for T
. Also Implement the Invoke
method or copy the method.
public class EnableMouseWheel : TargetedTriggerAction<Slider>
{
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
'.
- Copy the following code:
protected override void OnAttached()
{
base.OnAttached();
((FrameworkElement)AssociatedObject).MouseWheel +=
new MouseWheelEventHandler(SliderMouseScroll_MouseWheel);
}
protected override void OnDetaching()
{
base.OnDetaching();
((FrameworkElement)AssociatedObject).MouseWheel -=
new MouseWheelEventHandler(SliderMouseScroll_MouseWheel);
}
void SliderMouseScroll_MouseWheel(object sender, MouseWheelEventArgs e)
{
if (e.Delta > 0)
{
Target.Value = Target.Value + Target.SmallChange;
}
else {
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
).
- 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
- Check to see that we have the Behavior and the description:
- Attach the
Behavior
to the Rectangle
and in the properties of the Behavior
, set the Target
to one of the sliders
.
- 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>
{
protected override void Invoke(object parameter)
{
}
protected override void OnAttached()
{
base.OnAttached();
((FrameworkElement)AssociatedObject).MouseWheel +=
new MouseWheelEventHandler(SliderMouseScroll_MouseWheel);
}
protected override void OnDetaching()
{
base.OnDetaching();
((FrameworkElement)AssociatedObject).MouseWheel -=
new MouseWheelEventHandler(SliderMouseScroll_MouseWheel);
}
void SliderMouseScroll_MouseWheel(object sender, MouseWheelEventArgs e)
{
if (e.Delta > 0)
{
Target.Value = Target.Value + Target.SmallChange;
}
else {
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();
AssociatedObject.MouseWheel += new MouseWheelEventHandler
(SliderMouseScroll_MouseWheel);
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.MouseWheel -= new MouseWheelEventHandler
(SliderMouseScroll_MouseWheel);
}
void SliderMouseScroll_MouseWheel(object sender, MouseWheelEventArgs e)
{
if (e.Delta > 0)
{
AssociatedObject.Value = AssociatedObject.Value +
AssociatedObject.SmallChange;
}
else {
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