Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

A Numeric Up Down Control for WPF

0.00/5 (No votes)
26 Dec 2010 1  
A Nmeric Up Down Control for WPF

Introduction

The article just deals with creating a simple numeric up down control for WPF. The control supports data binding, value changes with up and down keys along with the up and down buttons.

NBDemo.PNG

Prerequisites

  1. .NET Framework 3.5 or higher
  2. Windows XP, 2003, Vista, 2008

Creating the Control

The control consists of a text box and two buttons which can increment or decrement the value in the control. For creating the control, I am using VS 2008 SP1. Follow the steps provided below to create a numeric up down control.

Adding the Control

  1. Open VS 2008, go to File->New Project , choose a language and create a Windows Library Project.
  2. Add a new user control to the project by choosing user control from the WPF category.
  3. Name it NumericUpDownControl.
  4. Add a grid inside a border. The main control will be placed inside the border just to have an outline.
  5. In the grid, add the textbox along with the two button controls for up and down actions.

The XAML for the controls looks like:

<Grid Margin="1">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="20" />
        </Grid.ColumnDefinitions>
        
        <TextBox Name="TextBoxValue"
                 TextAlignment="Right"
	 Grid.Column="0"/>
        <StackPanel Orientation="Vertical"
		Grid.Column="1"
		VerticalAlignment="Center">
            <Button x:Name="Increase">
                <Image Source="Images/up.png" Height="3" Width="5"  />
            </Button>
            <Button x:Name="Decrease" >
                <Image Source="Images/down.png" Height="3" Width="5" />
            </Button>
        </StackPanel>
    </Grid> 

Adding Properties and Basic Events

This creates the basic look of the control. Let’s add some event handlers to the control. First of all, since it’s a numeric up down control, it’s necessary to validate for the text input and allow only numeric input.

For validating the input, I am using regex class on the ‘PreviewTextInput’. The event is fired when the textbox gets the text, perfect time to check and validate the input. Let’s define the regular expression and then add the event handler code. It’s good to have the Regex defined in the constructor because it’s used in the other events as well.

private void value_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
    var tb = (TextBox)sender;
    var text = tb.Text.Insert(tb.CaretIndex, e.Text);

    e.Handled = !_numMatch.IsMatch(text);
}

When PreviewTextInput is fired, the event contains the char that’s just entered by the user and it’s still not the part of the Text property of the Textbox, so let’s just insert the newly entered character and see if it fits our criteria.

But before adding more events, let’s add some basic properties to the control like, Maximum, Minimum. It’s a good practice to add the properties as a dependency property so that we can utilize the binding features.

Note: We can add a dependency property by using the snippet ‘propdp’.

/// <summary>
/// Maximum value for the Numeric Up Down control
/// </summary>
public int Maximum
{
    get { return (int)GetValue(MaximumProperty); }
    set { SetValue(MaximumProperty, value); }
}

// Using a DependencyProperty as the backing store for Maximum.  
// This enables animation, styling, binding, etc...
public static readonly DependencyProperty MaximumProperty =
    DependencyProperty.Register("Maximum", typeof(int), 
    typeof(NumericBox), new UIPropertyMetadata(100));
    
/// <summary>
/// Minimum value of the numeric up down control.
/// </summary>
public int Minimum
{
    get { return (int)GetValue(MinimumProperty); }
    set { SetValue(MinimumProperty, value); }
}

// Using a DependencyProperty as the backing store for Minimum.  
// This enables animation, styling, binding, etc...
public static readonly DependencyProperty MinimumProperty =
    DependencyProperty.Register("Minimum", typeof(int), 
    typeof(NumericBox), new UIPropertyMetadata(0));

Now let’s add the Value property which represents the value of the numeric up down control. We’ll be adding it just like the previous properties with just one additional param, i.e., the PropertyChangedCallback, so that we may know when the value is changed and we can set the Textbox’s Text property to the current value.

The code for the Value property looks like:

public int Value
{
    get
    {
        return (int)GetValue(ValueProperty);
    }
    set
    {
        TextBoxValue.Text = value.ToString();
        SetValue(ValueProperty, value);
    }
}

// Using a DependencyProperty as the backing store for Value. 
// This enables animation, styling, binding, etc...
public static readonly DependencyProperty ValueProperty =
    DependencyProperty.Register("Value", typeof(int), typeof(NumericBox),
      new PropertyMetadata(0, new PropertyChangedCallback(OnSomeValuePropertyChanged)));
      
private static void OnSomeValuePropertyChanged(
DependencyObject target, DependencyPropertyChangedEventArgs e)
{
    NumericBox numericBox = target as NumericBox;
    numericBox.TextBoxValue.Text = e.NewValue.ToString();
}

Now once the properties are in place, let's just add the rest of the button and TextBox events:

Value Changed Event: Let’s add a TextChanged event to the textbox and add the following code in the event handler.

private void value_TextChanged(object sender, TextChangedEventArgs e)
        {
            var tb = (TextBox)sender;
            if (!_numMatch.IsMatch(tb.Text)) ResetText(tb);
            Value = Convert.ToInt32(tb.Text);
            if (Value < Minimum) Value = Minimum;
            if (Value > Maximum) Value = Maximum;
            RaiseEvent(new RoutedEventArgs(ValueChangedEvent));
        } 

First the input is validated, then min and max values are validated. After that, a ValueChangedEvent is fired. The users can register the event on the source control to get notified when the value in the control is changed.

 // Value changed
        private static readonly RoutedEvent ValueChangedEvent =
            EventManager.RegisterRoutedEvent("ValueChanged", RoutingStrategy.Bubble,
            typeof(RoutedEventHandler), typeof(NumericBox));

        /// <summary>The ValueChanged event is called when the 
        /// TextBoxValue of the control changes.</summary>
        public event RoutedEventHandler ValueChanged
        {
            add { AddHandler(ValueChangedEvent, value); }
            remove { RemoveHandler(ValueChangedEvent, value); }
        } 

For increment and decrement buttons, all we have to do is to increment or decrement the ‘Value’ property and raise the respective event so that the user on the parent control can register the event for changes.

 private void Increase_Click(object sender, RoutedEventArgs e)
        {
            if (Value < Maximum)
            {
                Value++;
                RaiseEvent(new RoutedEventArgs(IncreaseClickedEvent));
            }}  
 //Increase button clicked
        private static readonly RoutedEvent IncreaseClickedEvent =
            EventManager.RegisterRoutedEvent("IncreaseClicked", RoutingStrategy.Bubble,
            typeof(RoutedEventHandler), typeof(NumericBox));

        /// <summary>The IncreaseClicked event is called when the 
        /// Increase button clicked</summary>
        public event RoutedEventHandler IncreaseClicked
        {
            add { AddHandler(IncreaseClickedEvent, value); }
            remove { RemoveHandler(IncreaseClickedEvent, value); }
        }

Final Touches

The basic control looks ready to roll. Just one thing is missing, i.e. support of Up And Down Keys which is quite needed. So let’s just add that support to the control as well.

Add a PreviewKeyDown Event to the TextBox and the code for the handler looks like:

/// <summary>
    /// Checking for Up and Down events and updating the value accordingly
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void value_PreviewKeyDown(object sender, KeyEventArgs e)
    {
        if (e.IsDown && e.Key == Key.Up && Value < Maximum)
        {
            Value++;
            RaiseEvent(new RoutedEventArgs(IncreaseClickedEvent));
        }
        else if (e.IsDown && e.Key == Key.Down && Value > Minimum)
        {
            Value--;
            RaiseEvent(new RoutedEventArgs(DecreaseClickedEvent));
        }
    } 

Using the Code

The control is pretty straight forward to use. The demo project attached shows a sample usage where the control is binded to an object. You can also set the value from the codebehind or XAML file.

  1. The control supports Maximum and Minimum values along with the value property which returns the current value.
  2. All the three properties mentioned above are dependency properties and hence can be bounded to the object. This is really helpful when you are working with the MVVM or similar pattern where the View layer is kept clean of the UI code.
  3. A sample XAML usage is shown below:
<nb:NumericBox Value="{Binding Age,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
    Minimum="5" Maximum="100" Margin="5"/>

C# Code

p = new Person { Age = 25 };
this.DataContext = p; 

Conclusion

This is a very simple implementation of a numeric up down control. You can feel free to use it anywhere you want. I may have overlooked something or some issues but if you find any of those, please feel free to post them here so the issues can be fixed.

History

  • 25 Dec 2010 - Article published

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here