Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / .NET Framework / New Users / July 2007

Tip: Looking for answers? Try searching our database.

MonthCalendar, when changing month + showing an msgbox, it loops..

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Vigylant - 02 Jul 2007 18:46 GMT
Well, make a new windows-application...
Put in a MonthCalendar, and put in this:

Public Class Form1

  Private Sub MonthCalendar1_DateChanged(ByVal sender As System.Object,
ByVal e As System.Windows.Forms.DateRangeEventArgs) Handles
MonthCalendar1.DateChanged

      MsgBox("problem")

  End Sub

End Class

Then start the program... See my problem?
Any way to fix this? :)
Peter Duniho - 02 Jul 2007 23:54 GMT
>    Private Sub MonthCalendar1_DateChanged(ByVal sender As System.Object,
> ByVal e As System.Windows.Forms.DateRangeEventArgs) Handles
[quoted text clipped - 6 lines]
> Then start the program... See my problem?
> Any way to fix this? :)

I'm going to take a wild guess and make the assumption that calling  
MsgBox() causes the DateChanged event to be raised again, which causes you  
to call MsgBox(), etc.

For future reference, you should skip the theatrics and actually  
_describe_ the problem you're having in your post.  You have no way of  
knowing for sure that someone else will see the same behavior that you  
are, and so you could get an answer to a completely different question  
from the one you thought you were asking.

All that said, I see at least a couple of options:

    * Don't call MsgBox() from within the event handler.  Use  
BeginInvoke() or similar mechanism to cause the message box to be  
displayed outside of the DateChanged event handling call stack.

    * Set a flag before you call MsgBox() the first time.  Don't call  
MsgBox() if the flag is set.

Also, not being a VB user, I don't know what MsgBox() maps to, but on the  
outside chance that it's _not_ exactly the same as using the  
Forms.MessageBox class, you might try that instead.  It's not really clear  
to me why displaying a message box would cause the DateChanged event to be  
raised, and maybe the Forms.MessageBox class avoids that behavior somehow.

Pete
Vigylant - 03 Jul 2007 00:18 GMT
Well, the thing that happens is that:

When the mouse is still clicked, the messagebox shows... Then, more and more
messageboxes show up, because apparently, the mouse hasent released the
"scrolling-button" (which changes the month, which like you said, raises the
event again and again)

I got a fix, and that was to execute the msgbox in a backgroundworker :)

Ill try your way with begininvoke, though, ive never used it before, but ill
give it a go :)

Thanks for the help..

> >    Private Sub MonthCalendar1_DateChanged(ByVal sender As System.Object,
> > ByVal e As System.Windows.Forms.DateRangeEventArgs) Handles
[quoted text clipped - 33 lines]
>
> Pete
Peter Duniho - 03 Jul 2007 00:45 GMT
> Well, the thing that happens is that:
>
[quoted text clipped - 4 lines]
> the
> event again and again)

For the record, you never mentioned that part of the problem in your  
original post.  You just said to "start the program".

I didn't bother trying to run your code because, well...to do so seemed  
pointless.  But you certainly left out some important detail there.

> I got a fix, and that was to execute the msgbox in a backgroundworker :)

How does that fix the behavior?  If the user continues to drag and change  
the month, I would expect that you would simply keep executing new message  
boxes in a background worker.

> Ill try your way with begininvoke, though, ive never used it before, but  
> ill
> give it a go :)

Given your newest information, I'm not sure BeginInvoke() would help, just  
as I'm not clear on why running the message box in a background worker  
helps.  From your description, the user really is doing something that  
causes the event to be raised, and every time the event is raised, you  
display a message box.

Until you stop doing that, it doesn't seem to me that it will matter how  
you display the message box.  It's not the act of displaying the message  
box that causes the event to be raised again, so changing how you display  
the message box isn't going to fix the problem.

You need to set a flag while the message box is displayed, and not show it  
again until the message box has been dismissed.

Personally, I think that wouldn't really be all that great a solution  
either.  IMHO, the _correct_ user interface is to not show the dialog  
until the user has released the mouse button.  For that, you will need to  
set a flag in the DateChanged event that is then checked later in the  
MouseUp event handler, and only then display the message box.

It's pretty bad UI to be popping up dialog boxes when the mouse button is  
still down.

Pete
Vigylant - 03 Jul 2007 01:00 GMT
Well, i really dont know how it works when the messagebox is in a
backgroundworker, but it does work.. It does solve the problem...

Only weird thing, the event is raised twice for some intriguing reason :P
Anyway, i just put in a check on the worker status, and it exits the sub if
its not finished, so the problem is solved...

Although, explain some more about the mouseup event, it sounds less messy ^^

> > Well, the thing that happens is that:
> >
[quoted text clipped - 45 lines]
>
> Pete
Peter Duniho - 03 Jul 2007 02:36 GMT
> [...]
> 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
Vigylant - 03 Jul 2007 12:14 GMT
Well, it would probably work, but ive decided to change that part of my
program, so that i wont need to display the messagebox...

Thanks for all the help anyway :)

> > [...]
> > Although, explain some more about the mouseup event, it sounds less  
[quoted text clipped - 160 lines]
>
> Pete

Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.