【问题标题】:How to reliably determine the PreferredSize for System.Windows.Forms.MonthCalendar control?如何可靠地确定 System.Windows.Forms.MonthCalendar 控件的 PreferredSize?
【发布时间】:2013-09-10 16:57:45
【问题描述】:

在我的表单上,我有一个System.Windows.Forms.TableLayoutPanel,其中我将System.Windows.Forms.Panel 设置为DockStyle.Fill,在面板中,有一个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;
}

【问题讨论】:

    标签: c# winforms .net-3.5 monthcalendar


    【解决方案1】:

    MonthCalendar 是一个“难”的控件。它用于 Windows 中高度可见的区域(时钟),因此在 Windows 版本之间进行了相当多的修改。它不可调整大小,并且它的大小因版本而异。

    所以,不,使用 Dock = Fill 肯定行不通,这需要控件可调整大小。 GetPreferredSize() 只能返回一个猜测值,它可能曾经在旧 Windows 版本上是正确的,但现在不是。

    您需要处理它的行为。直到创建控件的本机窗口之后,您才能知道它的真实大小。通常在表单的 Load 事件或控件的 OnCreateHandle() 方法中(如果您从它派生)。此时它的 Size 属性将是可靠的。您需要相应地调整其父控件。

    【讨论】:

    • 用被证明是答案的代码更新了原始问题。感谢您的指导。
    【解决方案2】:

    您可以通过询问日历的句柄来强制调整日历的大小:

    IntPtr h = calendar.Handle;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-15
      • 2012-08-03
      相关资源
      最近更新 更多