Slider Preview as Expression Blend 3 Behavior
Behaviors is one of the new features Expression blend 3 has introduced to make interactivity easy. Behavior allows us to wrap the interaction logic as a very discrete unit and attach to any UI elements. My previous blog post about Attaching preview behavior to a Slider control, is a good scenario to make as a Behavior. I have used Attached Dependency property as a technique to make it happen in the earlier post, though the concept is almost same but Blend Behavior gives a neat and clean abstraction. It also allows a Blend user to just drag-drop to any Slider control. So this is a great functionality which helps boost the re-usability in a cool way.
Problem : Create a behavior to display the value of a Slider control when hover over.
First step is to make a class which derived from Behavior class. public class PreviewSliderBehaviour : Behavior<Slider> Here I am explicitly giving Slider class as my targeted UI Element type since this behavior is meaningless to other elements. Now we need to override two methods of Behavior class, protected override void OnAttached() and protected override void OnDetaching() . I can subscribe mouse events in the OnAttached() method and unsubscribe the same in the OnDetaching() method.
protected override void OnAttached()
{
m_attachedObject = AssociatedObject;// Gives you the instance of the Slider you attached this behavior on to
if (m_attachedObject != null)
{
m_attachedObject.PreviewMouseMove += new System.Windows.Input.MouseEventHandler(item_PreviewMouseMove);
m_attachedObject.MouseLeave += new System.Windows.Input.MouseEventHandler(item_MouseLeave);
}
base.OnAttached();
}
/// Called when the behavior is removed from the DependencyObject
protected override void OnDetaching()
{
if (m_attachedObject != null)
{
m_attachedObject.PreviewMouseMove -= new System.Windows.Input.MouseEventHandler(item_PreviewMouseMove);
m_attachedObject.MouseLeave -= new System.Windows.Input.MouseEventHandler(item_MouseLeave);
}
base.OnDetaching();
}
The important logic lies in the MouseMove handler, it creates a ContentAdorner(a custom adorner, you can see in the source code) and sets the value calculated here to the ContentAdorner.Content property. This also sets the ContentAdorner’s placement point to the mouse point so that the adorner moves along with the mouse move.
void item_PreviewMouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
Slider slider = sender as Slider;
if (popup == null)
{
//Creates a new ContentAdorner with the given Style, Content Style is a Dependancy property of this behaviour
popup = new ContentAdorner(slider, ContentStyle);
AdornerLayer layer = AdornerLayer.GetAdornerLayer(slider);
layer.Add(popup);
}
popup.Visibility = Visibility.Visible;
//Finding out the PART_Track from the controltemplate of the Slider
Track _track = slider.Template.FindName("PART_Track", slider) as Track;
//Calculates the mouse position
Point position = e.MouseDevice.GetPosition(_track);
//This method gives the exact preview value of the Slider
double value = _track.ValueFromPoint(position);
if (slider.SmallChange != 0.0)
{
double diff = value % slider.SmallChange;
value -= diff;
}
//Setting the value as the content of the ContentAdorner
popup.Content = Math.Max(slider.Minimum, Math.Min(slider.Maximum, value));
position = e.GetPosition(slider);
position.Y = slider.ActualHeight / 2.0;
popup.PlacementOffset = position;
}
Now it is pretty easy to add this behavior to any Slider control, if you are in Expression Blend just opens the behavior tab and drag and drop this on to any Slider in the designer area. The XAML code will looks like,
<Slider x:Name="sld" Minimum="00" Maximum="100" SmallChange="0.5" IsSnapToTickEnabled="True" TickFrequency="0.5">
<i:Interaction.Behaviors>
<local:PreviewSliderBehaviour ContentStyle="{StaticResource PreviewStyle}"/>
</i:Interaction.Behaviors>
</Slider>
Few other links you may be interested to read about Behaviors
Comments
Silverlight Development Company