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