0

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

Florian Koch
  • 1,372
  • 1
  • 30
  • 49

1 Answers1

0

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;
}
Florian Koch
  • 1,372
  • 1
  • 30
  • 49
  • Can't we use spinner.Increment in place of 1 ? I really liked your answer, i did not think of setting max and min values to non seen values. Well, my workplace required this, i am pretty happy with what i did using only wpf. – Ece Naz Sefercioğlu Aug 10 '16 at 11:28
  • Yeah, you could always change the minimum and maximum to the user value +- the increment, that would solve the problem for values smaller than 1, but there would still be problems: let's say you have minimum 10 maximum 100 and increment 15, current value is 20 - if you hit decrement now, it will be set to 100, but for a real loop it should be 95 – Florian Koch Aug 10 '16 at 11:34
  • I have another idea, I'll edit my answer as soon as I've prepared the code snippet – Florian Koch Aug 10 '16 at 11:39
  • It looks cleaner and more practical. I only try to understand Spinner.Value parts, only that part. Is 1 stil changeable with Increment ? – Ece Naz Sefercioğlu Aug 10 '16 at 12:05
  • the +/-1 part made it "better" because with this, minimum and maximum aren't the same (if you were on 10, decrement of 1 would go to 100), but it can't be simply exchanged with the increment. Better would be, to just calculate without the +/- 1 (now the distance between Minimum and maximum is 0, so basically they are the same, it's just different for the direction you are approaching from). I'll edit my answer – Florian Koch Aug 10 '16 at 12:19
  • @EceNazSefercioğlu if my answer is a viable solution for you, please accept it so others can see this problem is solved – Florian Koch Aug 10 '16 at 12:50