【发布时间】:2021-02-07 13:16:41
【问题描述】:
目标是创建类似于this question 的屏幕截图的 DateTimePicker。
第一次尝试覆盖 OnPaint:
public class MyDateTimePicker : DateTimePicker
{
private Image _image;
public MyDateTimePicker() : base()
{
SetStyle(ControlStyles.UserPaint | ControlStyles.ResizeRedraw |
ControlStyles.DoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);
}
[Browsable(true)]
public override Color BackColor
{
get
{
return base.BackColor;
}
set
{
base.BackColor = value;
}
}
[Category("Appearance")]
public Color BorderColor { get; set; } = Color.Black;
[Category("Appearance")]
public Color TextColor { get; set; } = Color.Black;
[Category("Appearance")]
public Image Image
{
get
{
return _image;
}
set
{
_image = value;
Invalidate();
}
}
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
// Fill the Background
e.Graphics.FillRectangle(new SolidBrush(this.BackColor), 0, 0, ClientRectangle.Width, ClientRectangle.Height);
// Draw DateTime text
e.Graphics.DrawString(this.Text, this.Font, new SolidBrush(TextColor), 5, 2);
// Draw Icon
if (_image != null)
{
Rectangle im_rect = new Rectangle(ClientRectangle.Width - 20, 2, ClientRectangle.Height - 4, ClientRectangle.Height - 4);
e.Graphics.DrawImage(_image, im_rect);
}
// Draw Border
e.Graphics.DrawRectangle(Pens.Black, new Rectangle(0, 0, ClientRectangle.Width - 1, ClientRectangle.Height - 1));
}
}
此解决方案存在以下问题:日期字段不可点击、使用箭头键更改日期时出现文本伪影、按钮的可点击区域变窄。
第二个解决方案覆盖 WndProc:
public class MyDateTimePicker : DateTimePicker
{
private const int WM_PAINT = 0x000F;
private Color _borderColor = Color.Black;
public MyDateTimePicker() { }
[Category("Appearance")]
public Color BorderColor
{
get { return _borderColor; }
set
{
if (_borderColor != value)
{
_borderColor = value;
this.Invalidate();
}
}
}
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case WM_PAINT:
base.WndProc(ref m);
using (var g = Graphics.FromHwnd(m.HWnd))
{
var rect = new Rectangle(0, 0, this.ClientSize.Width - 1, this.ClientSize.Height - 1);
g.DrawRectangle(new Pen(this.BorderColor), rect);
}
m.Result = IntPtr.Zero;
break;
default:
base.WndProc(ref m);
break;
}
}
}
此解决方案缺少按钮的自定义。也许有人知道如何以这种方式自定义按钮,或者如何解决第一个解决方案的问题?
如果可能的话,我想更改 DateTimePicker 的高度以匹配 ComboBox 的高度(目前它们相差 1px)。
【问题讨论】:
-
参见此处:How can I set the DateTimePicker dropdown to select Years or Months only?
OnDropDown()覆盖,您可以在其中获得 MonthCalendar 控件的句柄和ShowMonCalToday(),您可以在其中使用发送消息自定义其样式。 -- 您可以使用其句柄将 MonthCalendar 附加到 NativeWindow 并覆盖 WndProc 以绘制其部分。 -- 关于按钮,您必须在绘制 DateTimePicker 的其他部分时绘制它。参见,例如,Reza Aghaei 的回答 here。 -
感谢@Jimi 的回复!您能否建议如何使用 WndProc 强制不绘制原始按钮?
-
我检查了这个:我想改变 DateTimePicker 的高度以匹配 ComboBox 的高度(目前它们相差 1px)。 → 我检查了这个。我没有看到任何区别,可能是因为使用 125% 作为显示的缩放比例,还使用 app.manifest 在我的应用程序中启用了 dpiaware。
-
顺便说一下,我在 GitHub 上上传了我的代码的扩展版本。随意克隆/下载并基于此自定义。
标签: c# .net winforms datetimepicker