[...]
Although, explain some more about the mouseup event, it sounds less
messy ^^
Well, it turns out I don't have a great suggestion there after all.
I did a little checking on the MonthCalendar control, and found it to have
a couple of problems. One is that you don't reliably get a DateChanged
event when clicking and dragging within the control. It seems that
generally, you have to drag within the same week to get the event (and to
change the date...to be clear, it seems to be that the date itself isn't
changing...when the date does change, the event does seem to be raised).
This may be explaining why you do not always get a new message box
instance when dragging. Not all dragging causes the date to change.
It also has some pretty serious redraw issues when dragging. Yuck!
The more problematic issue is that the very first time that clicking and
dragging occurs within the control, the DateChanged event is raised before
the MouseDown event. Oops. Via the standard event-handling mechanism,
you don't find out early enough about the mouse interaction to avoid doing
anything in the event handler itself. So your only options are to bypass
the standard event handling mechanism, or to defer _everything_. I prefer
the latter (I think it's a little cleaner, and I try to avoid using the
WndProc override whenever possible), but here's an example of both, just
in case:
To bypass the event handling mechanism, you have to subclass the
MonthCalendar control, so that you have direct access to the WndProc. I
suppose if you wanted, you could expose new events driven by what's going
on in the WndProc, but given that you have to subclass anyway, I figure
it's simplest to just put everything in the subclassed control.
(sorry, C#...if I can try to read your VB code, you can try to read my C#
code
)...
public partial class MyMonthCalendar1 : MonthCalendar
{
public MyMonthCalendar1()
{
InitializeComponent();
}
private bool _fDateChanged;
private bool _fMouseDown;
protected override void OnDateChanged(DateRangeEventArgs drevent)
{
base.OnDateChanged(drevent);
if (_fMouseDown)
{
// Only defer the display of the message box if the mouse
is captured
// (Capture is true when the control has "captured" the
mouse, in response
// to the user clicking in the control)
_fDateChanged = true;
}
else
{
// Otherwise, just go ahead and show the message box (if,
for example,
// the value changed programmatically)
_ShowMessage();
}
}
void _ShowMessage()
{
// do your actual message box here
MessageBox.Show("Here's a message");
}
const int WM_LBUTTONDOWN = 0x0201;
const int WM_LBUTTONUP = 0x0202;
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case WM_LBUTTONDOWN:
_fMouseDown = true;
break;
case WM_LBUTTONUP:
if (_fDateChanged)
{
// Still bad form to put modal behavior in event
handlers, so use
// BeginInvoke to make sure that the
_ShowMessage() method isn't
// actually run until back at the main event loop
BeginInvoke(new MethodInvoker(_ShowMessage));
_fDateChanged = false;
}
_fMouseDown = false;
break;
}
base.WndProc(ref m);
}
}
Here's another alternative, which involved deferring any work until after
all of the current event processing is done (essentially, queue up a
request to show the dialog in the form's message queue, so that by the
time that request is actually executed, you've had time to observe the
mouse-down event). Note that the code may call BeginInvoke() multiple
times while clicking and dragging the mouse, but none of those should
result in the message-box being shown; only the one that's invoked from
the mouse-up handler will do that, since by the time it gets processed,
the _fMouseDown flag will have been reset:
public partial class Form1 : Form
{
private bool _fDateChanged;
private bool _fMouseDown;
public Form1()
{
InitializeComponent();
}
private void myMonthCalendar11_MouseDown(object sender,
MouseEventArgs e)
{
_fMouseDown = true;
}
private void myMonthCalendar11_MouseUp(object sender,
MouseEventArgs e)
{
if (_fDateChanged)
{
BeginInvoke(new MethodInvoker(_ShowMessage));
_fDateChanged = false;
}
_fMouseDown = false;
}
private void _ShowMessage()
{
if (!_fMouseDown)
{
MessageBox.Show("A message");
_fDateChanged = false;
}
}
private void myMonthCalendar11_DateChanged(object sender,
DateRangeEventArgs e)
{
_fDateChanged = true;
// A slight optimization here would be to only call
BeginInvoke() if
// !_fMouseDown; I suspect any performance advantage would be
minimal though
BeginInvoke(new MethodInvoker(_ShowMessage));
}
}
Hope that helps.
Pete