Introduction
Did you ever need a button that mimics the auto-repeat behavior of the keyboard? Button, that when clicked and held, emits a sequence of MouseDown
events as long as the button is pressed.
I needed such a button in my program. As usual, I started my search with CodeProject, and found an interesting article .NET port of Joe's AutoRepeat Button class by Nish Sivakumar. The presented code did its job and I was about to copy and paste it to my project when I realized that I can implement the desired functionality using simpler logic and with fewer lines of code.
Background
The basic idea is the same as in the original article: timer control periodically executes code that simulates multiple MouseDown
events as long as the button is pressed down.
The Code
Since I promised that it is simple and quick to implement, let's start.
First, I created the RepeatButton
user control inherited from the Button
.
public class RepeatButton : Button
Second, I added a Timer
control and renamed it to timerRepeater
. For a start, I added an empty tick event handler:
private void timerRepeater_Tick(object sender, EventArgs e)
{
}
Third, I defined two new properties to control repeat timing:
[DefaultValue(400)]
public int InitialDelay { set; get; }
[DefaultValue(62)]
public int RepeatInterval { set; get; }
I've made sure that properties are properly initialized in the constructor:
public RepeatButton():base()
{
InitializeComponent();
InitialDelay = 400;
RepeatInterval = 62;
}
Next, I overrode the OnMouseDown
event handler. The new code does three things:
- It saves the event argument to an external variable. This is needed because the event actually will be handled by the
timerRepeat_Tick
event handler that needs this information. - It makes sure that
timerRepeater
is disabled. This line of code is not really needed since timerRepeater
is always disabled when OnMouseDown
is executed. I added it here for clarity of code. - It calls
timerRepeater_Tick
that will immediately handle the initial click and all repetitions as long as the mouse is kept down.
MouseEventArgs MouseDownArgs = null;
protected override void OnMouseDown(MouseEventArgs mevent)
{
MouseDownArgs = mevent;
timerRepeater.Enabled = false;
timerRepeater_Tick(null, EventArgs.Empty);
}
And finally, the key element of code where repeat loop is happening. Time to fill timerRepeater_Tick
with usable code.
This handler is called explicitly from OnMouseDown
when the user presses button down. The first line contains a call to base.OnMouseDown
. This is where the actual MouseDown
event is handled and where the code that hosts the control gets notified that the mouse was pressed down.
Next
If timerRepeater
is not enabled (when timerRepeater_Tick
is called from OnMouseDown
, it is never enabled), it means that this code is called for the first time after the mouse was pressed down. In such a case, timerRepeater.Interval
is set to InitialDelay
, otherwise it is set to RepeatInterval
.
And finally in the last line of code, the timerRepeater.Enabled
property is set to true
. This will cause timerRepeater_Tick
to be continuously called at intervals of time set in the Interval
property.
private void timerRepeater_Tick(object sender, EventArgs e)
{
base.OnMouseDown(MouseDownArgs);
if (timerRepeater.Enabled)
timerRepeater.Interval = RepeatInterval;
else
timerRepeater.Interval = InitialDelay;
timerRepeater.Enabled = true;
}
The above piece of code will be called forever after the mouse is initially pressed down. We need to stop this behavior as soon as the mouse is up again. Nothing simpler. One extra line in OnMouseUp
is needed that sets the timerRepeater.Enabled
property to false
. This will stop the timerRepeater_Tick
loop instantly.
protected override void OnMouseUp(MouseEventArgs mevent)
{
base.OnMouseUp(mevent);
timerRepeater.Enabled = false;
}
And that's all, fully functional RepeatButton
in probably even less than 10 minutes.
The entire code for RepeatButton
is presented below, so you can copy it and paste to your solution:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.ComponentModel;
namespace RepeatButtonControl
{
public class RepeatButton : Button
{
private Timer timerRepeater;
private IContainer components;
public RepeatButton():base()
{
InitializeComponent();
InitialDelay = 400;
RepeatInterval = 62;
}
[DefaultValue(400)]
public int InitialDelay { set; get; }
[DefaultValue(62)]
public int RepeatInterval { set; get; }
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.timerRepeater = new System.Windows.Forms.Timer(this.components);
this.SuspendLayout();
this.timerRepeater.Tick += new System.EventHandler(this.timerRepeater_Tick);
this.ResumeLayout(false);
}
MouseEventArgs MouseDownArgs = null;
protected override void OnMouseDown(MouseEventArgs mevent)
{
MouseDownArgs = mevent;
timerRepeater.Enabled = false;
timerRepeater_Tick(null, EventArgs.Empty);
}
private void timerRepeater_Tick(object sender, EventArgs e)
{
base.OnMouseDown(MouseDownArgs);
if (timerRepeater.Enabled)
timerRepeater.Interval = RepeatInterval;
else
timerRepeater.Interval = InitialDelay;
timerRepeater.Enabled = true;
}
protected override void OnMouseUp(MouseEventArgs mevent)
{
base.OnMouseUp(mevent);
timerRepeater.Enabled = false;
}
}
}
Using the Code
You can code along repeating all steps described in the article and develop a repeat button from scratch, it's easy and fun.
If you want to save time, you can also download the attached source code. It contains the RepeatButton
source code and demo application illustrating the behavior of the repeat button. Not much explanation needed.
You press the repeatButton
on the demo main screen, hold it, and watch how events are generated as in the screenshot shown below:
The downloadable zip file contains also help file (chm). Please note that since you are downloading this file from the Internet, in order to use it you have to unblock it first. You can do it from Windows explorer: right click on the help file, select 'Properties', click 'Unblock' button.
History
- August 1, 2013 - Initial release
- September 17, 2013 - Updated source code: improved style, added comments, added the
Dispose
method, added help file for control (chm) - December 13, 2013 - Minor article text improvements