0

I am creating my own NumericUpDown control in VB. Here is my XAML:

<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             x:Class="NumericUpDown"
             mc:Ignorable="d" 
             d:DesignHeight="30" d:DesignWidth="100">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="20" />
            <ColumnDefinition Width="20" />
        </Grid.ColumnDefinitions>
        <TextBox x:Name="txtNum" Grid.Column="0" x:FieldModifier="private" TextChanged="txtNum_TextChanged"/>
        <Button x:Name="cmdDown" Grid.Column="1" x:FieldModifier="private" Content="˅" Width="20" Click="cmdDown_Click" />
        <Button x:Name="cmdUp" Grid.Column="2" x:FieldModifier="private" Content="˄" Width="20" Click="cmdUp_Click" />
    </Grid>
</UserControl>

And here is the VB code behind it:

Class NumericUpDown

    Dim _Minimum As Double = 0
    Dim _Maximum As Double = 100

    Private Sub NumericUpDown()
        InitializeComponent()
        txtNum.Text = Numeric
    End Sub

    Public Property Maximum As Double
        Get
            Return _Maximum
        End Get
        Set(value As Double)
            _Maximum = value
        End Set
    End Property

    Public Property Minimum As Double
        Get
            Return _Minimum
        End Get
        Set(value As Double)
            _Minimum = value
        End Set
    End Property

    Public Shared ReadOnly NumericProperty As DependencyProperty = DependencyProperty.Register("Numeric", GetType(String), GetType(NumericUpDown), _
        New PropertyMetadata(""))

    Public Property Numeric As String
        Get
            Return CType(GetValue(NumericProperty), String)
        End Get
        Set(value As String)
            SetValue(NumericProperty, value)
        End Set
    End Property

    Private Sub cmdUp_Click(sender As Object, e As RoutedEventArgs)
        Dim NumValue As Double
        NumValue = Val(txtNum.Text)
        NumValue += 1
        If NumValue > Maximum Then NumValue = Maximum
        txtNum.Text = NumValue.ToString
    End Sub

    Private Sub cmdDown_Click(sender As Object, e As RoutedEventArgs)
        Dim NumValue As Double
        NumValue = Val(txtNum.Text)
        NumValue -= 1
        If NumValue < Minimum Then NumValue = Minimum
        txtNum.Text = NumValue.ToString
    End Sub

    Private Sub txtNum_TextChanged(sender As Object, e As TextChangedEventArgs)
        Numeric = txtNum.Text
    End Sub
End Class

I use it in my page like this: Put this on page definition:

xmlns:local="clr-namespace:Demo"

And put this in the content section:

<local:NumericUpDown Numeric="{Binding Path=score, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>

Of course I have already set DataContext on the container and all other databound controls work as they should. But the textbox in my custom control turned out empty! It doesn't end here. When I type something in the textbox and when I give it some value using decrease and increase button, the value is transferred to my DataTable; which means this usercontrol does work to some extend. Where did I do wrong? Why won't the Textbox content be initialized with the starting value?

After a little more testing. It seems that my usercontrol doesn't work in 'Two-Way'. It doesn't receive data from DataTable, it only propagates value to it. How do I fix it?

1
  • unrelated, and primarily opinion based comment: NumericUpDown sucks. That's probably the main reason WPF doesn't have that. The buttons are too small and hard to click, and completely unusable in a touch device. You'd be better off by registering a class event handler for MouseWheel and increasing/decreasing your values based on that. Just a suggestion. Commented May 23, 2014 at 15:37

1 Answer 1

2

The issue is that you are not binding the Text property of txtNum to your Numeric property.

<TextBox x:Name="txtNum" Grid.Column="0" x:FieldModifier="private"
            Text="{Binding Path=Numeric, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"/>

Then you can remove txtNum_TextChanged, and modify your up/down click handlers to just update the Numeric property, e.g.:

Private Sub cmdUp_Click(sender As Object, e As RoutedEventArgs)
    If Me.Numeric < Me.Maximum Then
        Me.Numeric += 1
    Else
        Me.Numeric = Me.Maximum
    End If
End Sub

Private Sub cmdDown_Click(sender As Object, e As RoutedEventArgs)
    If Me.Numeric > Me.Minimum Then
        Me.Numeric -= 1
    Else
        Me.Numeric = Me.Minimum
    End If
End Sub

Note that there are still lots of issues - a user can enter a value outside of the allowed range, or non-numeric data (which will break things!), etc. For this specific problem, you could check out the Extended EPF Toolkit, which has various up/down controls.

Sign up to request clarification or add additional context in comments.

1 Comment

About that, WPF seems to be smart enough to mark the usercontrol with Red color when the end-user typed string into it, probably related to column's definition in DataTable. I kept TextChanged event handler to prevent user typing in out of range value. Thanks for your kind answer. Most tutorials out there use C# instead of VB. I should probably switch my language too...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.