I want to repeat an action when a Button
is pressed during a long time, like for example the forward button of an MP3 reader. Is there an existing c# event in W
shortest way (and without any task/thread/timer & stopwatch) :)
DateTime sw;
bool buttonUp = false;
const int holdButtonDuration = 2000;
private void btnTest_MouseDown(object sender, MouseEventArgs e)
{
buttonUp = false;
sw = DateTime.Now;
while (e.Button == MouseButtons.Left && e.Clicks == 1 && (buttonUp == false && (DateTime.Now - sw).TotalMilliseconds < holdButtonDuration))
Application.DoEvents();
if ((DateTime.Now - sw).TotalMilliseconds < holdButtonDuration)
Test_ShortClick();
else
Test_LongClick();
}
private void btnTest_MouseUp(object sender, MouseEventArgs e)
{
buttonUp = true;
}
I can handle the MouseDown event to start a timer which will perform the action and stop it on MouseUp event, but I am looking for an easier way to solve this problem.
You can make it easier by writing it once in a reusable way. You could derive your own Button
class that has this behaviour.
Or write a class that you can attach to any button to give it this behaviour. For example you could do something like:
class ButtonClickRepeater
{
public event EventHandler Click;
private Button button;
private Timer timer;
public ButtonClickRepeater(Button button, int interval)
{
if (button == null) throw new ArgumentNullException();
this.button = button;
button.MouseDown += new MouseEventHandler(button_MouseDown);
button.MouseUp += new MouseEventHandler(button_MouseUp);
button.Disposed += new EventHandler(button_Disposed);
timer = new Timer();
timer.Interval = interval;
timer.Tick += new EventHandler(timer_Tick);
}
void button_MouseDown(object sender, MouseEventArgs e)
{
OnClick(EventArgs.Empty);
timer.Start();
}
void button_MouseUp(object sender, MouseEventArgs e)
{
timer.Stop();
}
void button_Disposed(object sender, EventArgs e)
{
timer.Stop();
timer.Dispose();
}
void timer_Tick(object sender, EventArgs e)
{
OnClick(EventArgs.Empty);
}
protected void OnClick(EventArgs e)
{
if (Click != null) Click(button, e);
}
}
You would then use it as follows:
private void Form1_Load(object sender, EventArgs e)
{
ButtonClickRepeater repeater = new ButtonClickRepeater(this.myButton, 1000);
repeater.Click += new EventHandler(repeater_Click);
}
or more concisely, since you don't need to keep a reference to ButtonClickRepeater
:
private void Form1_Load(object sender, EventArgs e)
{
new ButtonClickRepeater(this.myBbutton, 1000).Click += new EventHandler(repeater_Click);
}
You will need to perform some action while the button is pressed, like skipping some seconds in the MP3-track.
Starting a timer that gets cancelled on mouseUp that triggers that kind of work on a regular interval (100ms?) while the button is down seems viable to me. Easy to implement and is non blocking on the UI.
A more simple solution will probably cause the UI to block.
You can use timer between MouseDown and MouseUp.
MouseDownEvent
Timer tm1;
MouseUpEvent
Timer tm2;
You can easily handle them between two timers.
UPDATED: Shortest way:
Using Anonymous Methods and Object Initializer
:
public void Repeater(Button btn, int interval)
{
var timer = new Timer {Interval = interval};
timer.Tick += (sender, e) => DoProgress();
btn.MouseDown += (sender, e) => timer.Start();
btn.MouseUp += (sender, e) => timer.Stop();
btn.Disposed += (sender, e) =>
{
timer.Stop();
timer.Dispose();
};
}