1
votes

I'd like to make a slider control that when I press a key (lets say shift), its thumb (and its value) will drag slower than the mouse and so become more precise.

I'm still new to WPF and I don't really where to start.

Any hints?

EDIT---

Here is what I'm trying so far with horizontal slider :

    Point pStart;
    Point pCurrent;

    private void CMiXSlider_DragDelta(object sender, DragDeltaEventArgs e)
    {
        if (Keyboard.IsKeyDown(Key.LeftShift))
        {
            pCurrent = Mouse.GetPosition(CMiXSlider);
            double center = Math.Abs(pCurrent.X - pStart.X);
            Value = (1.0 / CMiXSlider.ActualWidth) * center;
        }
    }

    private void CMiXSlider_DragStarted(object sender, DragStartedEventArgs e)
    {
            pStart = Mouse.GetPosition(CMiXSlider);
    }

it behaves almost as expected but the thumb is always at the center position between 0 and pCurrent. Looks like pStart doesn't keep its value when DragDelta is triggered.

2

2 Answers

2
votes

This is primarily a UX question, and only secondarily a WPF question. I cannot help you with WPF, but I can give you some input from a UX point of view.

Don't.

Just don't do this. It is a bad idea, for a number of reasons:

a) It is highly non-standard. No application that I ever heard of does something like that. Therefore, nobody will know that your slider behaves differently when some modifier key is pressed, and nobody will ever try to drag your slider with a modifier key down.

b) You cannot teach users to do it. Cluttering your user interface with additional text labels containing instructions on how to use it is clunky and abandoned as a practice decades ago.

c) Even if you do somehow manage to teach users to do it, the mental effort of learning some new way to use an existing and familiar control is not worth the added benefit of simply having better control over the precision of the slider.

d) This could either work by moving the slider by a fraction of the distance by which the pointer moves, or by slowing down the pointer.

  • moving the slider by a fraction of the distance by which the pointer moves would look ugly and clunky. It would work, but it would look broken.

  • slowing down the pointer is a tricky proposition, and it would only work with a mouse. What about a touch interface where the user uses their finger? You can't slow that down.

Solutions:

  1. Implement movement by arrow keys. That's the standard way of allowing fine control over the value of a slider. When the slider has focus, then the arrow keys should change the value by one unit.

  2. If the nature of your application is such that high precision is of great importance, then consider replacing the slider with a numeric control. Make it a spinner if need be. (A numeric control with an up and down button.) Or perhaps make it a numeric control with a drop-down slider, so the primary means of operation is numeric, and operation by slider is secondary and optional. (I have no idea how nor if you can do that with WPF.)

0
votes

Sometimes this functionality is useful, for example a lighting/audio control or fine positioning of robotic arms. In these UX situations users will probably find out by RTFM.

I'm not in front of a PC, here is some simple psuedo code to illustrate how to do it with a Custom Slider Control that ignores every second value change when the shift key is down.

public class CustomSlider : Slider 
{ 
  private int precision = 2;
  private int movement = 0;
  protected override void OnValueChanged(double oldValue, double newValue) 
  {
    bool keyShift = (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift)) 

    if (keyShift && movement % precision == 0)
    {
      base.OnValueChanged(oldValue, newValue); 
    }
    else if (!keyShift)
    {
      base.OnValueChanged(oldValue, newValue); 
    }

    movement++;
    if (movement == int.MaxValue) movement = 0;
 }
}

You could apply this solution to Numeric Up/Down, Scroll Bars and various other controls.

In addition to the code above, for even more precise interaction you can detect for Ctrl key in the OnValueChanged event and increase precision, eg

precision = Keyboard.IsKeyDown(Key.Control) ? 3 : 2;