如何可靠地确定 System.Windows.Forms.MonthCalendar 控件的首选大小
本文关键字:控件 MonthCalendar Forms Windows 何可 System | 更新日期: 2023-09-27 18:30:46
在我的窗体上,我有一个System.Windows.Forms.TableLayoutPanel
,其中我有一个设置为DockStyle.Fill
System.Windows.Forms.Panel
,在面板中,一个System.Windows.Forms.MonthCalendar
控件(也设置为填充)。
日历是一个继承的控件,只是为了允许重写主题,以便我可以设置颜色等。 继承的部分来自另一个 SO 问题,我已经忘记了。
代码:
public class NativeMethods
{
[DllImport("uxtheme.dll")]
public static extern Int32 SetWindowTheme(IntPtr hWnd, String appname, String idlist);
}
public class CustomMonthCalendar : MonthCalendar
{
public CustomMonthCalendar()
{
InitializeComponent();
Margin = new Padding(0);
}
private void InitializeComponent()
{
SuspendLayout();
ResumeLayout(false);
}
protected override void OnHandleCreated(EventArgs e)
{
NativeMethods.SetWindowTheme(Handle, String.Empty, String.Empty);
base.OnHandleCreated(e);
}
}
public class CustomCalendar : UserControl
{
DayPickerControl = new CustomMonthCalendar();
DayPickerControl.ForeColor = SystemColors.ControlText;
DayPickerControl.BackColor = BackgroundColor;
DayPickerControl.TitleForeColor = TextColor.Lighten(1.2f);
DayPickerControl.TitleBackColor = BackgroundColor;
DayPickerControl.TrailingForeColor = Color.Gray;
DayPickerControl.Dock = DockStyle.Fill;
DayPickerControl.FirstDayOfWeek = Day.Sunday;
DayPickerControl.Font = new Font("Microsoft Sans Serif", 9f, FontStyle.Regular);
DayPickerControl.MaxDate = new DateTime(2999, 12, 31, 0, 0, 0, 0);
DayPickerControl.MaxSelectionCount = 7;
DayPickerControl.MinDate = new DateTime(1900, 1, 1, 0, 0, 0, 0);
DayPickerControl.ScrollChange = 1;
DayPickerControl.SetCalendarDimensions(1, 1);
DayPickerControl.ShowToday = true;
DayPickerControl.ShowTodayCircle = true;
DayPickerControl.Text = null;
DayPickerPanel = new Panel();
DayPickerPanel.BorderStyle = BorderStyle.None;
DayPickerPanel.Dock = DockStyle.Fill;
DayPickerPanel.Location = new Point(0, 0);
DayPickerPanel.Padding = new Padding(2);
Size prefSize = DayPickerControl.GetPreferredSize(new Size(200, 200));
DayPickerPanel.Size = new Size(prefSize.Width + 5, prefSize.Height + 5);
DayPickerPanel.Paint += panelBorder_Paint;
DayPickerPanel.Controls.Add(DayPickerControl);
}
因此,问题是关于确定日历控件想要的大小。 无论我做什么,我从GetPreferredSize()
那里得到的尺寸总是178, 155
。 但是,在屏幕上,日历的右边缘是截断的,这意味着它比停靠的面板大。 这在我看来,它也可能不太关心停靠。 不确定。
我已经摆弄了各种停靠/未停靠与锚定设置,但结果总是相同的。
为什么我得到的尺寸看似不正确? 我如何确定适合它的正确尺寸?
编辑:使用Hans Passant的建议,我得出了这个解决方案:
//A new event in the CustomMonthCalendar class
public event EventHandler<AfterHandleCreatedArgs> AfterHandleCreated;
//A modified version of the OnHandleCreated() method shown above (add event call)
protected override void OnHandleCreated(EventArgs e)
{
NativeMethods.SetWindowTheme(Handle, String.Empty, String.Empty);
base.OnHandleCreated(e);
if (this.IsHandleCreated && AfterHandleCreated != null)
AfterHandleCreated(this, new AfterHandleCreatedArgs(new Size(this.Size.Width + 5, this.Size.Height + 5))); //cosmetic padding
}
//A new class for the event args it passes...
public class AfterHandleCreatedArgs : EventArgs
{
private Size _newSize = Size.Empty;
public Size NewSize { get { return _newSize; } set { _newSize = value; } }
public AfterHandleCreatedArgs(Size newSize)
{
_newSize = newSize;
}
}
//And a handler to attach to that new event (in CustomCalendar class)...
private void DayPickerControl_AfterHandleCreated(Object sender, AfterHandleCreatedArgs e)
{
if (!e.NewSize.Equals(Size.Empty))
DayPickerPanel.Size = e.NewSize;
}
MonthCalendar 是一个"困难"的控件。 它用于Windows(时钟)中高度可见的区域,因此在Windows版本之间进行了相当多的修改。 它不可调整大小,其大小因版本而异。
所以,不,使用 Dock = Fill 肯定行不通,这需要控件可调整大小。 GetPreferredSize() 只能返回一个 guestimate,一个在旧 Windows 版本上可能曾经正确的估计,但今天不是。
您将需要处理其行为。 在创建控件的本机窗口之前,您无法知道其真实大小。 通常在窗体的 Load 事件或控件的 OnCreateHandle() 方法中(如果您从它派生)。 此时,其 Size 属性将是可靠的。 您需要相应地调整其父控件。
您可以通过请求日历的句柄来强制日历调整其大小:
IntPtr h = calendar.Handle;