Click here to Skip to main content
Licence CPOL
First Posted 9 Oct 2009
Views 7,032
Bookmarked 4 times

Silverlight Behaviors and Triggers: Making a True Behavior

By | 9 Oct 2009 | Technical Blog
Learn how to create reusable behaviors in Silverlight that can be attached through code or even with Expression Blend.
A Technical Blog article. View original blog here.[^]

We have explored using dependency properties and attached properties to abstract behaviors and triggers. In my last article, TextBox Magic, I showed how to create a dependency property to enable a textbox filter that would prevent anything but digits. In this article, we'll take it a step further and turn it into a "true" behavior.

A "true" behavior inherits from Behavior. The first step is to add a reference to System.Windows.Interactivity. There are a number of nice things about using the behavior system that make them more flexible to use than basic dependency properties. First, the behaviors can integrate with Expression Blend. You can define a behavior, import it into the tool, and literally drag it onto a control to attach the behavior. Second, behaviors automatically provide overrides to tap into the attach/detach events. Third, behaviors are typed to their target controls: you may have a generic behavior that targets FrameworkElement or a specific behavior that targets TextBox. Finally, we can decorate behaviors with attributes that are discovered by Intellisense and available when attaching the behavior.

We are going to create a filter behavior. The first step is to simply inherit from the base behavior class and then override the pertinent events:

public class TextBoxFilterBehavior : Behavior<TextBox>
{
   protected override void OnAttached()
   {
       AssociatedObject.KeyDown += _TextBoxFilterBehaviorKeyDown;
   }

   protected override void OnDetaching()
   {
       AssociatedObject.KeyDown += _TextBoxFilterBehaviorKeyDown; 
   }
}

As you can see, we have a convenient place to hook into the KeyDown event and unhook at the end. We also have a nice, typed AssociatedObject to use and manipulate.

We'll extend our filter to handle alpha (alphanumeric and spaces), positive numeric digits, and regular numeric digits. For the regular numeric digits, we'll allow the subtract/minus sign only if it's the very first character in the text. The "helper" methods look like this:

private static readonly List<key> _controlKeys = new List<Key>
                                                     {
                                                         Key.Back,
                                                         Key.CapsLock,
                                                         Key.Ctrl,
                                                         Key.Down,
                                                         Key.End,
                                                         Key.Enter,
                                                         Key.Escape,
                                                         Key.Home,
                                                         Key.Insert,
                                                         Key.Left,
                                                         Key.PageDown,
                                                         Key.PageUp,
                                                         Key.Right,
                                                         Key.Shift,
                                                         Key.Tab,
                                                         Key.Up
                                                     };

private static bool _IsDigit(Key key)
{
    bool shiftKey = (Keyboard.Modifiers & ModifierKeys.Shift) != 0;
    bool retVal;
    if (key >= Key.D0 && key <= Key.D9 && !shiftKey)
    {
        retVal = true;
    }
    else
    {
        retVal = key >= Key.NumPad0 && key <= Key.NumPad9;
    }
    return retVal;
}

static bool _HandleNumeric(string text, Key key)
{
    bool handled = true;
    
    // if empty, allow minus - only can be first character
    if (string.IsNullOrEmpty(text.Trim()) && key.Equals(Key.Subtract))
    {
        handled = false;
    }
    else if (_controlKeys.Contains(key) || _IsDigit(key))
    {
        handled = false;
    }

    return handled;
}

static bool _HandlePositiveNumeric(Key key)
{
    bool handled = true;

    if (_controlKeys.Contains(key) || _IsDigit(key))
    {
        handled = false;
    }

    return handled;
}

static bool _HandleAlpha(Key key)
{
    bool handled = true;

    if (_controlKeys.Contains(key) || _IsDigit(key) || key.Equals(Key.Space) ||
        (key >= Key.A && key <= Key.Z))
    {
        handled = false;
    }

    return handled;
}

public enum TextBoxFilterType
{
    AlphaFilter,
    PositiveNumericFilter,
    NumericFilter
}

public TextBoxFilterType FilterType { get; set; }

As you can see, the familiar list of "friendly" keys is carried over. There are some helper methods for our different types of filters, as well as an enumeration. The enumeration gives us the flexibility of determining which filter to use and then a property is exposed to set that enumeration.

The last step is to wire in the actual event:

void _TextBoxFilterBehaviorKeyDown(object sender, KeyEventArgs e)
{
    switch(FilterType)
    {
        case TextBoxFilterType.AlphaFilter:
            e.Handled = _HandleAlpha(e.Key);
            break;

        case TextBoxFilterType.NumericFilter:
            e.Handled = _HandleNumeric(AssociatedObject.Text, e.Key);
            break;

        case TextBoxFilterType.PositiveNumericFilter:
            e.Handled = _HandlePositiveNumeric(e.Key);
            break;
    }
}

As you can see, it's as simple as checking the enumeration, calling the helper function and modifying the handled property.

Now we can reference the project with our behavior and reference the System.Windows.Interactivity. In XAML, you attach the behavior like this:

<TextBox>
   <Interactivity:Interaction.Behaviors>
      <Behaviors:TextBoxFilterBehavior FilterType="AlphaFilter"/>
   </Interactivity:Interaction.Behaviors>
</TextBox>

As you can see, easy to add, easy to read quickly what the behavior does, and the added bonus is that you can manipulate these in Expression Blend.

Jeremy Likness

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Jeremy Likness

Architect
Wintellect
United States United States

Member

Follow on Twitter Follow on Twitter
Jeremy Likness is a Microsoft Silverlight MVP who works as Project Manager and Senior Consultant for Wintellect with 15 years of experience developing enterprise applications. He has worked with software in multiple verticals ranging from insurance, health and wellness, supply chain management, and mobility. His primary focus for the past decade has been building highly scalable web-based solutions using the Microsoft technology stack with a focus on Silverlight since version 2.0.
 
Prior to Wintellect, Jeremy was Director of Information Technology and served as development manager and architect for AirWatch, LLC, where he helped the company grow and solidify its position as one of the leading wireless technology solution providers in the United States by managing the development of their product portfolio that includes public HotSpot solutions and a management console for enterprise grade wireless networks, mobile devices, and their consumers. A fluent Spanish speaker, Jeremy served as Director of Information Technology for Hispanicare, where he architected a multi-lingual content management system for the company's Hispanic-focused online diet program. Jeremy accepted his role there after serving as Development Manager for Manhattan Associates, a software company that provides supply chain management solutions.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
GeneralTypo in first snippet PinmemberValentin Ivanov5:30 23 Sep '10  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web01 | 2.5.120517.1 | Last Updated 9 Oct 2009
Article Copyright 2009 by Jeremy Likness
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid