Adding Global Behaviors to Silverlight Controls
Take a look at the two buttons below, and hover your mouse over them. You’ll notice that the buttons hide themselves.
However, when you take a look at the XAML, it is not obvious how this is implemented.
<UserControl x:Class="GlobalBehavior.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:local="clr-namespace:GlobalBehavior"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<Button Content="Click Me" Margin="36,28,0,0" HorizontalAlignment="Left" Width="112" Height="47" VerticalAlignment="Top" />
<Button Content="Click Me" Margin="133,104,0,0" HorizontalAlignment="Left" Width="112" Height="47" VerticalAlignment="Top" />
</Grid>
</UserControl>
This is done by attaching a behavior to the default Button style. There is a little wrinkle to the trick. The style setters by default is not able to set complex attached dependency properties. However, it can handle simple dependency properties. So, we’d write a simple depedency property that can be attached like this:
<Style TargetType="Button">
<Setter Property="local:HideButtonBehavior.ButtonBehaviors" Value="True" />
</Style>
and the ButtonBehaviors dependency property sets the actual Behaviors on the button.
namespace GlobalBehavior
{
using System;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interactivity;
using System.Windows.Media;
using System.Windows.Media.Animation;
public partial class HideButtonBehavior : Behavior<FrameworkElement>
{
#region HideButtonBehavior.ButtonBehaviors depedency property
public static bool GetButtonBehaviors(DependencyObject obj)
{
return (bool)obj.GetValue(ButtonBehaviorsProperty);
}
public static void SetButtonBehaviors(DependencyObject obj, bool value)
{
obj.SetValue(ButtonBehaviorsProperty, value);
}
// Using a DependencyProperty as the backing store for ButtonBehaviors.
public static readonly DependencyProperty ButtonBehaviorsProperty =
DependencyProperty.RegisterAttached("ButtonBehaviors",
typeof(bool), typeof(Button), new PropertyMetadata(false, ButtonBehaviorsChanged));
private static void ButtonBehaviorsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var behaviors = Interaction.GetBehaviors(d);
var existingBehavior = behaviors.FirstOrDefault(b => b.GetType() ==
typeof(HideButtonBehavior)) as HideButtonBehavior;
if ((bool)e.NewValue == false && existingBehavior != null)
{
behaviors.Remove(existingBehavior);
}
else if ((bool)e.NewValue == true && existingBehavior == null)
{
/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
/* !!! THE REST ARE ALL BOILERPLATE. THE REAL GOODNESS IS HERE !!! */
behaviors.Add(new HideButtonBehavior());
/* !!! !!! */
/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
}
}
#endregion
}
}
and for completeness, here’s the code for the silly Button behavior.
namespace GlobalBehavior
{
using System;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interactivity;
using System.Windows.Media;
using System.Windows.Media.Animation;
public partial class HideButtonBehavior : Behavior<FrameworkElement>
{
#region Custom Button Behavior
protected override void OnAttached()
{
base.OnAttached();
Button button = this.AssociatedObject as Button;
button.RenderTransform = new ScaleTransform();
button.MouseMove += button_MouseMove;
}
protected override void OnDetaching()
{
Button button = this.AssociatedObject as Button;
button.MouseMove -= button_MouseMove;
base.OnDetaching();
}
void button_MouseMove(object sender, MouseEventArgs e)
{
DoubleAnimationUsingKeyFrames anim = new DoubleAnimationUsingKeyFrames();
anim.KeyFrames.Add(new LinearDoubleKeyFrame() { Value = 0.0, KeyTime = TimeSpan.FromMilliseconds(150) });
anim.KeyFrames.Add(new LinearDoubleKeyFrame() { Value = 0.0, KeyTime = TimeSpan.FromMilliseconds(2000) });
anim.KeyFrames.Add(new LinearDoubleKeyFrame() { Value = 1.0, KeyTime = TimeSpan.FromMilliseconds(2150) });
Storyboard.SetTarget(anim, this.AssociatedObject);
Storyboard.SetTargetProperty(anim, new PropertyPath("(UIElement.RenderTransform).(ScaleTransform.ScaleY)"));
Storyboard sb = new Storyboard();
sb.Children.Add(anim);
sb.Begin();
}
#endregion
}
}
Acknowledgements
This technique is first discovered by julmar
About this entry
You’re currently reading “ Adding Global Behaviors to Silverlight Controls ,” an entry on Chui's Counterpoint
- Published:
- 2.26.13 / 1pm
- Category:
- Silverlight
Comments are closed
Comments are currently closed on this entry.