Click here to Skip to main content
15,891,633 members
Articles / Programming Languages / C#

Silverlight Behaviors and Triggers: Making a True Behavior

Rate me:
Please Sign up or sign in to vote.
4.00/5 (4 votes)
9 Oct 2009CPOL2 min read 15.6K   4   1
Learn how to create reusable behaviors in Silverlight that can be attached through code or even with Expression Blend.

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:

C#
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:

C#
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:

C#
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:

XML
<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)


Written By
Program Manager Microsoft
United States United States
Note: articles posted here are independently written and do not represent endorsements nor reflect the views of my employer.

I am a Program Manager for .NET Data at Microsoft. I have been building enterprise software with a focus on line of business web applications for more than two decades. I'm the author of several (now historical) technical books including Designing Silverlight Business Applications and Programming the Windows Runtime by Example. I use the Silverlight book everyday! It props up my monitor to the correct ergonomic height. I have delivered hundreds of technical presentations in dozens of countries around the world and love mentoring other developers. I am co-host of the Microsoft Channel 9 "On .NET" show. In my free time, I maintain a 95% plant-based diet, exercise regularly, hike in the Cascades and thrash Beat Saber levels.

I was diagnosed with young onset Parkinson's Disease in February of 2020. I maintain a blog about my personal journey with the disease at https://strengthwithparkinsons.com/.


Comments and Discussions

 
GeneralTypo in first snippet Pin
Valentin Ivanov23-Sep-10 5:30
professionalValentin Ivanov23-Sep-10 5:30 

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

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