WinFormsのコントロールのClickとDoubleClickに別のアクションを割り当てたいことはわりとある。しかし、DoubleClickが発火するときは、最初のクリックでClickが発火するため、DoubleClickにはClickのアクションを前提とするアクションしか割り当てられない。
そこで、DoubleClickのときはClickのアクションを実行しないように、最初のClickのアクションの実行をダブルクリックの間隔まで遅延させて、DoubleClickが発火したらClickのアクションを実行しない振る舞いを実装してみた。
private readonly SemaphoreSlim _clickSemaphore = new SemaphoreSlim(1);
private readonly SemaphoreSlim _doubleClickSemaphore = new SemaphoreSlim(0);
private async void OnClick(object sender, EventArgs e)
{
if (!_clickSemaphore.Wait(0))
return;
try
{
if (await _doubleClickSemaphore.WaitAsync(SystemInformation.DoubleClickTime))
return;
}
finally
{
_clickSemaphore.Release();
}
// クリックのアクション
}
private void OnDoubleClick(object sender, EventArgs e)
{
_doubleClickSemaphore.Release();
// ダブルクリックのアクション
}
ここでは二つセマフォを使っていて、_clickSemaphore
はダブルクリック待ちの間に再入を防止する。_doubleClickSemaphore
はダブルクリック待ちと同時にダブルクリックが実行されたことの判別も行う。
Microsoftに同じの趣旨のHow to: Distinguish Between Clicks and Double-Clicksという記事があったけど、まったく使えない内容だったのでカッとなって書いた。