Although a bit of a hack, this effect is actually pretty simple to achieve by extending RepeatButton as long as your desired interval can always be expressed as an integer multiple of some constant base interval.
Here is a quick example of how this can be done:
public class AcceleratingRepeatButton : System.Windows.Controls.Primitives.RepeatButton
{
private int _intervalCount = -1;
protected override void OnClick()
{
//Always OnClick for the initial press
if (_intervalCount < 0) {
_intervalCount = -1;
base.OnClick();
} else if (ShouldTriggerRepeat(_intervalCount)) {
base.OnClick();
}
_intervalCount += 1;
}
protected override void OnIsPressedChanged(DependencyPropertyChangedEventArgs e)
{
_intervalCount = -1; //When the button is released, reset the counter
base.OnIsPressedChanged(e);
}
private bool ShouldTriggerRepeat(int count)
{
const int intervalsAtQuarterRate = 16; //For the first 16 intervals, trigger repeats at 1/4 the normal rate
const int intervalsAtHalfRate = 16 + intervalsAtQuarterRate; //the next 16 intervals at 1/2 the rate
if (count < intervalsAtQuarterRate) {
return (count & 7) == 0; //Returns true every 4 intervals
} else if (count < intervalsAtHalfRate) {
return (count & 3) == 0; //Returns true every 2 intervals
} else {
return true;
}
}
}
Dependency properties can be used to allow configuration from xaml (excluded in favor of brevity), and more complex logic can be used within ShouldTriggerRepeat to allow more fine-tuned control.