It's a weird behavior, that changing BorderStyle
of a picture box will stop the click to propagate (a Click
event will always raise before DoubleClick
event).
I do not really know how to handle it properly, but we could do some hack to make the feature work. We can introduce a "lag" between a Click
and DoubleClick
to make the DoubleClick
is checked before Click
.
Here we use a Timer
to do the job:
private Timer _timer;
private PictureBox _sender;
private int _clicks;
public Form1()
{
InitializeComponent();
pictureBox.Click += picutureClick;
pictureBox.DoubleClick += (s, e) =>
{
// do your double click handling
_clicks = 0;
};
// this Interval comes from trail and error, it's a balance between lag and
// correctness. To play safe, you can use SystemInformation.DoubleClickTime,
// but may introduce a bit long lagging after you click and before you
// see the effects.
_timer = new Timer {Interval = 75};
_timer.Tick += (s, e) =>
{
if (_clicks < 2)
{
ClickHandler(_sender);
}
_clicks = 0;
_timer.Stop();
};
}
private void picutureClick(Object sender, EventArgs e)
{
_clicks++;
_sender = (PictureBox) sender;
if (_clicks == 1)
{
_timer.Start();
}
}
private void ClickHandler(PictureBox picture)
{
if (picture.BorderStyle == BorderStyle.None)
{
// this line is not thread safe, but you could comment out the .InvokeIfRequire()
// and uncomment this line to have a look at your form's behavior
//picture.BorderStyle = BorderStyle.Fixed3D;
picture.InvokeIfRequired(c => (c as PictureBox).BorderStyle = BorderStyle.Fixed3D);
picture.BackColor = Color.Red;
}
else
{
// same for this
//picture.BorderStyle = BorderStyle.Fixed3D;
picture.InvokeIfRequired(c => (c as PictureBox).BorderStyle = BorderStyle.None);
picture.BackColor = Color.White;
}
}
In the above code, I used an extension method to handle cross-thread property updating:
public static void InvokeIfRequired(this Control c, Action<Control> action)
{
if (c.InvokeRequired)
{
c.Invoke(new Action(() => action(c)));
}
else
{
action(c);
}
}
Edit:
The extension method I used above is to simplify the code written to do cross-thread property update. More details on this topic can be found here: Automating the InvokeRequired code pattern
Here are some details on Extension Method:
An extension method only works if it's declared in a non-generic, non-nested static class. To make it work, you need to declare a new public static class
to hold the method.
// your form class declared here
public partial class Form1 : Form
{
// code omitted here
}
// declare the extension method in this extension class
public static class ControlExtensions
{
public static void InvokeIfRequired(this Control c, Action<Control> action)
{
if (c.InvokeRequired)
{
c.Invoke(new Action(() => action(c)));
}
else
{
action(c);
}
}
}