Daniel Wu Daniel Wu - 5 months ago 70
Vb.net Question

WPF NumericUpDown usercontrol in VB.net

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?

Answer

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.

Comments