Ece Naz Sefercio─člu Ece Naz Sefercio─člu - 3 months ago 37
C# Question

How to create a looping doubleUpDown from extended WPF Toolkit?

I have a task that I should make a number spinner which also loops through max min values if a checkbox is checked, derived from extended WPF Toolkit's doubleUpDown. Is there a way i can understand increment spin button or decrement spin button is pushed? So that i could give needed controls to my number spinner?

Documentation of DoubleUpDown

I made a number spinner but only using WPF, i should make one with extended toolkit.

enter image description here

Answer

It seems the DoubleUpDown doesn't provide events for clicks on the Up-/Down-Buttons. But (from the Documentation you linked):

ValueChanged: Raised when the Value changes. (Inherited from UpDownBase)

The value changed event could help you out. In this case, you could try setting the minimum always 1 lower and the maximum 1 higher then what the user entered in the textboxes, and check for these values in the ValueChanged event to achieve the "loop". Not the prettiest solution, though.

I created a small example. The relevant xaml:

<xctk:DoubleUpDown x:Name="Spinner" ClipValueToMinMax="True" Minimum="9" Maximum="21" Value="15" Increment="{Binding ElementName=Increment, Path=Text}" ValueChanged="UpDownBase_OnValueChanged"/>
<TextBox x:Name="Min" TextChanged="Min_OnTextChanged" Text="10"/>
<TextBox x:Name="Max" TextChanged="Max_OnTextChanged" Text="20"/>
<TextBox x:Name="Increment" Text="1"/>

And the code behind (xaml.cs):

private void UpDownBase_OnValueChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
    if ((double) e.NewValue == Spinner.Minimum)
        Spinner.Value = Spinner.Maximum - 1;
    else if ((double) e.NewValue == Spinner.Maximum)
        Spinner.Value = Spinner.Minimum + 1;
}

private void Min_OnTextChanged(object sender, TextChangedEventArgs e)
{
    double minimum;
    if (double.TryParse(Min.Text, out minimum))
        Spinner.Minimum = minimum - 1;
}

private void Max_OnTextChanged(object sender, TextChangedEventArgs e)
{
    double maximum;
    if (double.TryParse(Max.Text, out maximum))
        Spinner.Maximum = maximum + 1;
}

The biggest problem with this is, however, that it doesn't work great with increment values other than 1. E.g., if you are at the minimum and want to decrease by more than one, it will still go to the maximum. Even worse, when using an increment smaller than 1, yo can go below your minimum until the increment reachs the minimum - 1 we use to check this. So if you want to allow doubles and not only integers this solution won't work for you at all.

I think the best solution would be to create an own UserControl like you did, because you are trying to alter the original functionality significantly. Why do you need to use the DoubleUpDown?


Another way would be to not use the minimum and maximum properties at all and handle the calculation yourself each time the ValueChanged event occurs - this would solve the problems of the above solution.

XAML:

<xctk:DoubleUpDown x:Name="Spinner" Value="15" Increment="{Binding ElementName=Increment, Path=Text}" ValueChanged="UpDownBase_OnValueChanged"/>
<TextBox x:Name="Min" TextChanged="Min_OnTextChanged"/>
<TextBox x:Name="Max" TextChanged="Max_OnTextChanged"/>
<TextBox x:Name="Increment" Text="1"/>

xaml.cs

public MainWindow()
{
    InitializeComponent();
    Min.Text = _currentMinimum.ToString();
    Max.Text = _currentMaximum.ToString();
}

private double _currentMinimum = 10;
private double _currentMaximum= 100;

private void UpDownBase_OnValueChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
    if ((double) e.NewValue < _currentMinimum)
        Spinner.Value = (double)e.NewValue + (_currentMaximum - _currentMinimum);
    else if ((double) e.NewValue > _currentMaximum)
        Spinner.Value = (double)e.NewValue - (_currentMaximum - _currentMinimum);
}

private void Min_OnTextChanged(object sender, TextChangedEventArgs e)
{
    double minimum;
    if (double.TryParse(Min.Text, out minimum))
        _currentMinimum = minimum;
}

private void Max_OnTextChanged(object sender, TextChangedEventArgs e)
{
    double maximum;
    if (double.TryParse(Max.Text, out maximum))
        _currentMaximum= maximum;
}