5

I'm trying to create a DateTimePicker with week numbers displayed, as shown here (Code project example).

It works fairly well, except for one minor detail; The calender popping up when trying to select a date is not the right size. As you can see, the calendar area is sort of "cramped", especially along the right edge.

enter image description here

I can click the bottom right corner here, and drag it out a little - just enough to expand it so that it looks right:

enter image description here

I can't seem to find any way to force the calendar to be the correct/full size from the beginning, or to resize it.

Kjartan
  • 18,591
  • 15
  • 71
  • 96
  • try to modify the fonts-size of `DataTimePicker`. – spajce Jan 28 '13 at 13:34
  • Tried it, didn't help. Working on a solution resizing the parent frame / window at the moment. Apparently, there are two (possibly more?) "layers" of windows inside the calender. Somehow the inner one is the right size, but not the outer one... – Kjartan Jan 28 '13 at 13:41
  • http://reflector.webtropy.com/default.aspx/Dotnetfx_Win7_3@5@1/Dotnetfx_Win7_3@5@1/3@5@1/DEVDIV/depot/DevDiv/releases/whidbey/NetFXspW7/ndp/fx/src/WinForms/Managed/System/WinForms/DateTimePicker@cs/1/DateTimePicker@cs – Mohammad Arshad Alam Jan 28 '13 at 14:45

3 Answers3

7

Finally found a solution that seems to work - at least for now.

It seems there are two windows in the calendar part of the DateTimePicker. Apparently my code would automatically find the correct size for the inner one (more or less at least?), but not the outer one.

A bit of research has led to the code below. The following links provide some useful and relevant info:

The trick was to add a little to the height and width of the (inner) window, then apply the same height and width to the outer window (which I access using the GetParrent() function). I found the "correct" size by trial and error: When the size matched what was needed for the contents of the calendar, it could not be resized any longer.

Yes, this feels a little like a hack, and no, I haven't been able to verify that it works perfectly on other computers than my own yet. I'm a little worried about having to give specific values for height and width, but I'm hoping this won't be affected by screen resolutions or whatever else.

Hope someone else in a similar situation will find the code useful.
(The following can directly replace a regular DateTimePicker to show week numbers in the calendar)

using System;
using System.ComponentModel;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;

public class DatePickerWithWeekNumbers : DateTimePicker
{
    [DllImport("User32.dll")]
    private static extern int GetWindowLong(IntPtr handleToWindow, 
                                            int offsetToValueToGet);

    [DllImport("User32.dll")]
    private static extern int SetWindowLong(IntPtr h, 
                                            int index, 
                                            int value);

    private const int McmFirst = 0x1000;
    private const int McmGetminreqrect = (McmFirst + 9);
    private const int McsWeeknumbers = 0x4;
    private const int DtmFirst = 0x1000;
    private const int DtmGetmonthcal = (DtmFirst + 8);


    [DllImport("User32.dll")]
    private static extern IntPtr SendMessage(IntPtr h,
                                             int msg, 
                                             int param, 
                                             int data);

    [DllImport("User32.dll")]
    private static extern IntPtr GetParent(IntPtr h);

    [DllImport("User32.dll")]
    private static extern int SendMessage(IntPtr h, 
                                          int msg,
                                          int param, 
                                          ref Rectangle data);

    [DllImport("User32.dll")]
    private static extern int MoveWindow(IntPtr h, 
                                         int x, 
                                         int y,
                                         int width, 
                                         int height, 
                                         bool repaint);

    [Browsable(true), DesignerSerializationVisibility(
        DesignerSerializationVisibility.Visible)]
    public bool DisplayWeekNumbers { get; set; }

    protected override void OnDropDown(EventArgs e)
    {
        // Hex value to specify that we want the style-attributes
        // for the window:
        const int offsetToGetWindowsStyles = (-16);

        IntPtr pointerToCalenderWindow = SendMessage(Handle, 
                                                     DtmGetmonthcal,  
                                                     0,  
                                                     0);
        int styleForWindow = GetWindowLong(pointerToCalenderWindow, 
                                           offsetToGetWindowsStyles);

        // Check properties for the control - matches available 
        // property in the graphical properties for the DateTimePicker:
        if (DisplayWeekNumbers)
        {
            styleForWindow = styleForWindow | McsWeeknumbers;
        }
        else
        {
            styleForWindow = styleForWindow & ~McsWeeknumbers;
        }

        // Get the size needed to display the calendar (inner window)
        var rect = new Rectangle();
        SendMessage(pointerToCalenderWindow, McmGetminreqrect, 0, ref rect);

        // Add to size as needed (I don't know why 
        // this was not correct initially!)
        rect.Width = rect.Width + 28;
        rect.Height = rect.Height + 6;

        // Set window styles..
        SetWindowLong(pointerToCalenderWindow, 
                      offsetToGetWindowsStyles, 
                      styleForWindow);

        // Dont move the window - just resize it as needed:
        MoveWindow(pointerToCalenderWindow, 
                   0, 
                   0, 
                   rect.Right, 
                   rect.Bottom, 
                   true);

        // Now access the parrent window..
        var parentWindow = GetParent(pointerToCalenderWindow);
        // ...and resize that the same way:
        MoveWindow(parentWindow, 0, 0, rect.Right, rect.Bottom, true);

        base.OnDropDown(e);
    }
}
Kjartan
  • 18,591
  • 15
  • 71
  • 96
  • dlls not getting added in the form – Mohammad Arshad Alam Jan 28 '13 at 14:48
  • after creating the usercontrol/dll , when i am adding it to the form from toolbox, its not rendering/adding . – Mohammad Arshad Alam Jan 28 '13 at 14:57
  • Try to add a regular `DateTimePicker` first. Once you've gotten that to work, replace `DateTimePicker x = new DateTimePicker();` with `DatePickerWithWeekNumbers x = new DatePickerWithWeekNumbers();`. That's what I did anyway. You don't need to create a separate DLL by the way, just include this as a class in the same project. – Kjartan Jan 28 '13 at 15:16
2

For me, setting MCS_WEEKNUMBERS via the DateTimePicker's DTM_SETMCSTYLE message automatically resulted in the correct size of the MonthCal control:

SendMessage(Handle, DTM_FIRST + 11, 0, SendMessage(Handle, DTM_FIRST + 12, 0, 0) | MCS_WEEKNUMBERS);

Where DTM_FIRST = 0x1000 and MCS_WEEKNUMBERS = 0x4 as in Kjartan's solution. DTM_FIRST + 11 is DTM_SETMCSTYLE and DTM_FIRST + 12 is DTM_GETMCSTYLE in Microsoft's documentation.

Unlike Kjartan's solution, this call must be used before the first dropdown, but right at form initialization didn't work for me in some cases, so I delayed it to when the form was already created and visible in these cases. One call is enough, the DateTimePicker will save the style for future dropdowns.

Janni
  • 21
  • 1
1

Ok, Try to comment line in Program.cs

Application.EnableVisualStyles();

and then try to execute.

byteboy
  • 107
  • 1
  • 10
  • This solved a problem I had where when I clicked the dropdown on the DateTimePicker, the pop-up would mostly never appear, and when it did, it would display either just as a single column, or so small that you cant do anything with this. Posting this here in case anyone else ever experiences that issue. I am using a lot of nested Custom Controls on my main form and I wonder if it is something to do with that. However, commenting this line 100% fixed my issue. – Davy C Feb 18 '19 at 10:50