Capture Month Change with MonthCalendar

  • Thread starter Thread starter Randy
  • Start date Start date
R

Randy

I have a MonthCalendar on one of my forms. I have disovered that the
DateChanged event is triggered not only when the user clicks on a new
date, but also if they click on the Previous or Next Month arrows
(meaning they click on either of the left or right pointing arrows in
the top corner). If the user changes the month, it messes up some of
the date logic that I have in the DateChanged event. Does anybody
know how I can capture this action? I'd like my code in the
DateChanged routine to work like this:

If MonthNotChanged then
Do Something
Else 'month changed
Do something Else
End if

Thanks,
Randy
 
Randy,

Did you try the other events, I use always the TextChanged one?

Cor
 
I don't see TextChanged in the list of events. I looked at the other
events, but I don't see anything that is more appropriate.
 
Bear in mind that I am a proud Framework 1.0 knuckledragger...

Also bear in mind that I only tested this using the month calendar in single
month display mode.

Also note that you probably cannot use message boxes in the datechanged
event handler...It caused bizarre behavior that I could not manage even by
dynamically removing and re-adding the event handler. Instead, this test
code monitors values in the text property of the form, which displays in the
title bar.

Also the event processes twice, but with the If and EsleIf statements, as
written, they only evaluate to true once.

All that said, here goes...

When the user clicks on one of the month arrows, the selected date changes
to the same day of the month in the next or previous month.

Here is code that uses that fact to monitor user clicks of the month change
buttons.

Private CurrentSelectedDate As DateTime = Date.Today

Private Sub Form1_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
Me.MonthCalendar1.SelectionStart = Me.MonthCalendar1.TodayDate
Me.CurrentSelectedDate = Me.MonthCalendar1.TodayDate
End Sub

Private Sub MonthCalendar1_DateChanged(ByVal sender As System.Object, _
ByVal e As System.Windows.Forms.DateRangeEventArgs) _
Handles MonthCalendar1.DateChanged
Dim d As DateTime = e.Start
If d.AddMonths(-1) = Me.CurrentSelectedDate Then
Me.Text = d.ToString & " Right arrow clicked."
ElseIf d.AddMonths(1) = Me.CurrentSelectedDate Then
Me.Text = d.ToString & " Left arrow clicked."
End If
Me.CurrentSelectedDate = d
End Sub

Does this work?
 
Charlie,
I was going down the same path with using an If statement to check if
the month had changed. Unfortunately, this doesn't always work. If
you look at the calendar view, you can often see the last few days of
the previous month or the first few days of the succeeding month. If
the user were to click on these dates, the logic you propose would
conclude that the user had clicked the arrow, not the date. I'll post
my code below for anybody who is interested.

What I am trying to do is execute certain lines of code *only* if the
user has selected a date. If they are clicking on one of the arrows,
I am treating this action as the user *navigating* to a date (as
opposed to actually selecting one). So if they were to click Sep 28
while viewing the Oct calendar, this would qualify as *selecting* a
date, and thus would initiate a sequence of actions. If they clicked
the left arrow, this is simply a navigational move and would be
disregarded. I've looked for patterns in how the MonthCalendar
handles these arrow clicks, but I'm not seeing reliable patterns that
I can code around.

Somehow, the control must distinguish these arrows or it wouldn't work
as it does. So the question is still, how can I trap these clicks in
my VB code? If I can figure that out, it will make my programming
monumentally easier as well as more reliable.


Private Sub MonthCalendar1_DateChanged(ByVal sender As Object, ByVal e
As System.Windows.Forms.DateRangeEventArgs) Handles
MonthCalendar1.DateChanged
'If there are unsaved changes, alert the user
If bLoading = False Then
If bUnsaved = True Then
frmDateChange.Show()
Exit Sub
End If

'This is where I'm stuck trying to trap the arrow click
Dim d As Date = e.Start
'Me.Text = Me.CurrentSelectedDate
If d.AddMonths(-1).Month = Me.CurrentSelectedDate.Month
Then
If d.Day = 1 Then
Me.Text = d.ToString & " Right arrow clicked."
Call SelectDates()
End If
ElseIf d.AddMonths(1).Month = Me.CurrentSelectedDate.Month
Then
If d.Day = 1 Then
Me.Text = d.ToString & " Left arrow clicked."
Call SelectDates()
End If
Else
Me.Text = d.ToString & " Date changed."
Call SelectDates()
Call RemoveControls()
Call AddDataRows()
End If
Me.CurrentSelectedDate = d
End If
End Sub

Private Sub SelectDates()
Dim i As Integer =
CInt(MonthCalendar1.SelectionStart.DayOfWeek)
Dim d As Date = MonthCalendar1.SelectionStart
Dim a As Integer
If i = 0 Then
a = -6
Else
a = 1 - i
End If
MonthCalendar1.SelectionStart = d.AddDays(a)

If i = 0 Then
a = 0
Else
a = 7 - i
End If
MonthCalendar1.SelectionEnd = d.AddDays(a)
End Sub

So, how do I trap this arrow click? Or if there is no way, how can I
program the logic to identify and trap the conditions that would would
be present if the arrows are clicked? Any help is appreciated.

Thanks,
Randy
 
You could add another event handler to the code I previously provided...In
fact, this would probably do it on its own...

The MonthCalendar.MouseDown event (e as MouseEventArgs) captures the X and Y
coordinates relative to the control itself...My test shows that Y < 24 for a
click of the month buttons...
 
The mousedown event happens AFTER the datechanged event, so you may have to
capture any needed parameters in the datechanged event, and let the mousedown
event act on those parameters after determining where the user clicked...

As I was writing the previous note, I assumed the events processed in
reverse to how they actually process...Oh well, it really should not be much
of a problem.
 
And just in case you're not always depending on a mouse click for a date
change, you could use a timer to postpone the code of the datechanged event
(maybe 100 ms?, to see if the mouseclick occurred.
 
Thanks a lot, Charlie. These are great suggestions. I'm having a
little trouble implementing it, however, as I cannot get predictable
values for the coordinates where the arrows would have to exist.
Since this is a separate topic from just determining if the arrow has
been clicked, I started a new post. (search: Find Mouse Coordinates
Within Control). I'd appreciate if you have any ideas.

Thanks again for all of your help. I really appreciate it.
Randy
 
I revised the code you posted and tested it. I use VB.net 2002...ie
framework 1.0, but I think if you paste this into any vb.net form module, it
should work.

The first thing I saw that might have caused a problem was using
Timer.Enabled instead of Timer.Start.

What this code does is look for a 1 month change in date, and a click above
a certain Y coordinate. That coordinate should be a value that reflects
generally that the click occurred in the top part of the calendar. It could
vary depending on the font of the calendar because the font determines the
size of the calendar. My tests showed that a value of 35 would work for a
font size of 10, so that is what I used.

If you need to do precise measurements as to where the user clicked, the
tests for x and y can be done from the mousedown event, and shown for testing
purposes in the title bar. If you need to use precise measurements to
specifically identify that the user has clicked exactly on one arrow or the
other, remember that the coordinates will be specific to a given font setting.

[Also, I would recommend creating a form by specifically adding a windows
form to the project, rather than just adding a class that inherits the
windows form class.]

In testing, I noticed that if the user clicks on the year, or changes the
year, the mousedown event does not fire. That does not affect the specific
purpose of this code, but is worth noting for other variations.

Here's the code I tested. If you want to step through the code, you have to
put a separate breakpoint on the timer_tick event handler.

This code goes after the Windows Form designer generated code...

Private DateRangeEventArgs As DateRangeEventArgs
Private Ycoordinate As Int32 = -1
Private CurrentDate As DateTime
Private myTimer As New System.Windows.Forms.Timer()

Private Sub Form_Load(ByVal sender As Object, ByVal e As _
System.EventArgs) Handles MyBase.Load
AddHandler myTimer.Tick, AddressOf TimerEventProcessor
myTimer.Interval = 100
Me.MonthCalendar1.SelectionStart = Date.Today
Me.MonthCalendar1.SelectionEnd = Date.Today
Me.CurrentDate = Date.Today
End Sub

Private Sub MonthCalendar1_DateChanged(ByVal sender As Object, _
ByVal e As System.Windows.Forms.DateRangeEventArgs) Handles _
MonthCalendar1.DateChanged
Me.DateRangeEventArgs = e
myTimer.Start()
End Sub

Private Sub TimerEventProcessor(ByVal myObject As Object, ByVal _
myEventArgs As EventArgs)
myTimer.Stop()
Try
'Test if Date is 1 month different and whether user clicked in
the upper area
If Me.CurrentDate.AddMonths(1) = Me.DateRangeEventArgs.Start
AndAlso _
Me.Ycoordinate > -1 AndAlso Me.Ycoordinate < 35 Then
Me.Text = "Right Arrow Clicked"
ElseIf Me.CurrentDate.AddMonths(-1) =
Me.DateRangeEventArgs.Start AndAlso _
Me.Ycoordinate > -1 AndAlso Me.Ycoordinate < 35 Then
Me.Text = "Left Arrow Clicked"
Else
Me.Text = "No Arrow Clicked"
End If
'Reset form-wide variables and objects
Me.Ycoordinate = -1
Me.CurrentDate = Me.DateRangeEventArgs.Start
Me.DateRangeEventArgs = Nothing
Catch ex As Exception
MessageBox.Show(ex.Message & ex.StackTrace)
End Try
End Sub

Private Sub MonthCalendar1_MouseDown(ByVal sender As Object, ByVal _
e As System.Windows.Forms.MouseEventArgs) Handles _
MonthCalendar1.MouseDown
Me.Ycoordinate = e.Y
End Sub
End Class

Does this work?
 
This worked for me
If MousePosition.Y.ToString - Me.Top > 40 Then
Changed month
else
Changed day
end if



Randy wrote:

Capture Month Change with MonthCalendar
06-Oct-07

I have a MonthCalendar on one of my forms. I have disovered that th
DateChanged event is triggered not only when the user clicks on a ne
date, but also if they click on the Previous or Next Month arrow
(meaning they click on either of the left or right pointing arrows i
the top corner). If the user changes the month, it messes up some o
the date logic that I have in the DateChanged event. Does anybod
know how I can capture this action? I'd like my code in th
DateChanged routine to work like this

If MonthNotChanged the
Do Somethin
Else 'month change
Do something Els
End i

Thanks
Randy

EggHeadCafe - Software Developer Portal of Choice
WPF And The Model View View Model Pattern
http://www.eggheadcafe.com/tutorial...b-7374d3da3425/wpf-and-the-model-view-vi.aspx
 
Sorry, here is a better description
MonthCalendar1.MouseDown
If MousePosition.Y.ToString - Me.Top > 40 Then
Me.Tag = MonthCalendar1.SelectionStart
Me.Hide()
else
'Month change here'
End If

Since the mouse position is relative to the page, this makes it relative to the form the calendar is in.

Hope this helps.



Randy wrote:

Capture Month Change with MonthCalendar
06-Oct-07

I have a MonthCalendar on one of my forms. I have disovered that th
DateChanged event is triggered not only when the user clicks on a ne
date, but also if they click on the Previous or Next Month arrow
(meaning they click on either of the left or right pointing arrows i
the top corner). If the user changes the month, it messes up some o
the date logic that I have in the DateChanged event. Does anybod
know how I can capture this action? I'd like my code in th
DateChanged routine to work like this

If MonthNotChanged the
Do Somethin
Else 'month change
Do something Els
End i

Thanks
Randy

EggHeadCafe - Software Developer Portal of Choice
WPF And The Model View View Model Pattern
http://www.eggheadcafe.com/tutorial...b-7374d3da3425/wpf-and-the-model-view-vi.aspx
 
Wouldn't it be far easier to just store a static date variable in the
DateChanged event handler which holds the previous value, compare it to the
new value and step out if the month is different?

Whenever you start hard-coding mouse coordinates you open yourself up for a
world of pain on different screen resolutions, new versions of the control,
and different dimensions based on Windows theme settings or monitor DPI
settings.
 
Back
Top