Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
294 views
in Technique[技术] by (71.8m points)

c# - Setting calendar size when overriding DateTimePicker to add week numbers

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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);
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...