我正在尝试创建一个DateTimePicker
显示周数的项目,如此处所示(代码项目示例)。
它工作得相当好,除了一个小细节;尝试选择日期时弹出的日历大小不合适。如您所见,日历区域有点“狭窄”,尤其是在右边缘。
我可以单击此处的右下角,然后将其拖出一点 - 足以将其展开以使其看起来正确:
我似乎找不到任何方法来强制日历从一开始就正确/完整大小,或者调整它的大小。
我正在尝试创建一个DateTimePicker
显示周数的项目,如此处所示(代码项目示例)。
它工作得相当好,除了一个小细节;尝试选择日期时弹出的日历大小不合适。如您所见,日历区域有点“狭窄”,尤其是在右边缘。
我可以单击此处的右下角,然后将其拖出一点 - 足以将其展开以使其看起来正确:
我似乎找不到任何方法来强制日历从一开始就正确/完整大小,或者调整它的大小。
终于找到了一个似乎可行的解决方案——至少现在是这样。
日历部分似乎有两个窗口DateTimePicker
。显然,我的代码会自动找到内部的正确大小(至少或多或少?),但不是外部的。
一些研究导致了下面的代码。以下链接提供了一些有用且相关的信息:
诀窍是在(内部)窗口的高度和宽度上添加一点,然后将相同的高度和宽度应用于外部窗口(我使用该GetParrent()
函数访问)。我通过反复试验找到了“正确”的尺寸:当尺寸与日历内容所需的尺寸相匹配时,它就无法再调整大小了。
是的,这感觉有点像 hack,不,我还无法验证它是否可以在我自己的计算机之外的其他计算机上完美运行。我有点担心必须给出特定的高度和宽度值,但我希望这不会受到屏幕分辨率或其他任何东西的影响。
希望处于类似情况的其他人会发现该代码很有用。
(下面可以直接替换一个常规DateTimePicker
来显示日历中的周数)
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);
}
}
对我来说,MCS_WEEKNUMBERS
通过 DateTimePicker 的DTM_SETMCSTYLE
消息设置会自动产生正确的 MonthCal 控件大小:
SendMessage(Handle, DTM_FIRST + 11, 0, SendMessage(Handle, DTM_FIRST + 12, 0, 0) | MCS_WEEKNUMBERS);
在Kjartan 的解决方案中的位置DTM_FIRST = 0x1000
和位置。是并且在Microsoft 的文档中。MCS_WEEKNUMBERS = 0x4
DTM_FIRST + 11
DTM_SETMCSTYLE
DTM_FIRST + 12
DTM_GETMCSTYLE
与 Kjartan 的解决方案不同,此调用必须在第一个下拉菜单之前使用,但在某些情况下,在表单初始化时对我不起作用,所以我将其延迟到表单已经创建并在这些情况下可见的时候。一个电话就足够了,DateTimePicker 将保存样式以供将来的下拉菜单使用。
好的,尝试在 Program.cs 中注释行
Application.EnableVisualStyles();
然后尝试执行。