当Dock更改时,UserControl不在FlowLayoutPanel内呈现

时间:2011-09-15 19:51:43

标签: c# winforms anchor dock flowlayoutpanel

当我将UserControls添加到FlowLayoutPanel时,它们会正确显示。当我在添加它们之前更改UserControls上的Dock或Anchor属性时,它们仍然会被添加但不会渲染。

根据“How to: Anchor and Dock Child Controls”,这应该是可能的。

  • 我可以说控件已添加(尽管没有绘图),因为添加足够的控件会导致出现垂直滚动条。
  • 将UserControls的“Dock”属性设置为“Left”或“None”将导致它们呈现,但没有其他选项。
  • 将UserControls上的“Anchor”属性设置为除Top |之外的任何内容左边没有渲染。
  • 在添加控件之前或之后设置底座没有区别(Add,Dock vs. Dock,Add)。
  • FlowLayoutPanel本身是停靠(Fill),FlowDirection设置为TopDown,WrapContents设置为false,AutoScroll设置为true,否则默认为。

我使用的是.NET 3.5。


在回答评论时,两条注释行是我试图更改停靠点的位置。第二点肯定更有意义,但我尝试了另一个因为它不会受伤。

public void CreateObjectControl( object o )
{
    ObjectControl oc = new ObjectControl();

    oc.MyObject = o;

    //This was a spot I mentioned:
    //oc.Dock = DockStyle.Fill;

    ObjectDictionary.Add( o, oc );
    flowLayoutPanel1.Controls.Add( oc );

    //This is the other spot I mentioned:
    oc.Dock = DockStyle.Fill;
}

2 个答案:

答案 0 :(得分:0)

在进行任何需要呈现以进行正确查看的修改之前,尝试使用SuspendLayout和Resumelayout函数作为控件。

您可以在Designer.cs中看到该特定控件的代码

语法

control.SuspendLayout();
{Your code for designer amendments}
control.resumeaLayout();

答案 1 :(得分:0)

我想我可能找到了一个解决方法(读:脏伎俩)...... this answer帮我指明了正确的方向。以下是您与MS article相关联的摘录:

  

对于垂直流方向,FlowLayoutPanel控件计算列中最宽子控件的隐含列的宽度。具有Anchor或Dock属性的此列中的所有其他控件将对齐或拉伸以适合此隐含列。

     

对于水平流向,行为的工作方式类似。 FlowLayoutPanel控件计算行中最高子控件的隐含行的高度,此行中所有停靠或锚定的子控件都对齐或调整大小以适合隐含的行。

此页面没有特别提及您无法停靠/锚定最高/最宽控件。但是,由于此控件定义了FlowLayoutPanel的布局行为,从而影响了所有其他同级控件的显示方式,因此Dock和Anchor很可能无法正常运行“主控件”。即使我找不到任何关于此的官方文件,我相信也是如此。

那么,我们有哪些选择?在运行时,我们可以在添加usercontrol之前添加一个高度为0的面板控件和FlowLayoutPanel客户区的宽度。您甚至可以将该面板的可见性设置为false。订阅FlowLayoutPanel的一些Resize / Layout事件以保持该面板的大小将成为诀窍。但这在设计时并不能很好地发挥作用。事件不会触发,因此您无法按照您希望的方式设计表面。

我更喜欢在设计时“正常工作”的解决方案。所以,这里是一个“隐形”控件的尝试,我把它放在一起,如果没有其他控件存在,则将控件调整为零宽度。在设计时将此作为第一个控件放到FlowLayoutPanel上似乎提供了所需的效果,随后放在FlowLayoutPanel上的任何控件都可以向右固定而不缩小到零宽度。唯一的问题是,一旦这个不可见的控件存在,我似乎无法通过IDE删除它。可能需要使用ControlDesigner进行一些特殊处理才能实现这一目标。它仍然可以在表单的设计器代码中删除。

此控件一旦放入FlowLayoutPanel,将侦听其父控件的resize事件,并根据父控件的ClientSize调整自身大小。请谨慎使用,因为这可能包含在我玩这个游戏的几个小时内没有发生的陷阱。例如,我没有尝试放置比FlowLayoutPanel的客户区宽的控件。

作为旁注,仍然会失败的是试图锚定到底部,但这不是问题的一部分; - )

using System;
using System.Collections;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Windows.Forms;

namespace ControlTest
{
  public sealed class InvisibleControl : Control
  {
    public InvisibleControl()
    {
      TabStop = false;
    }

    #region public interface

    // Reduce the temptation ...
    public new AnchorStyles Anchor
    {
      get { return base.Anchor; }
      set { base.Anchor = AnchorStyles.None; }
    }
    public new DockStyle Dock
    {
      get { return base.Dock; }
      set { base.Dock = DockStyle.None; }
    }

    // We don't ever want to move away from (0,0)
    public new Point Location
    {
      get { return base.Location; }
      set { base.Location = Point.Empty; }
    }

    // Horizontal or vertical orientation?
    private Orientation _orientation = Orientation.Horizontal;
    [DefaultValue(typeof(Orientation), "Horizontal")]
    public Orientation Orientation
    {
      get { return _orientation; }
      set
      {
        if (_orientation == value) return;
        _orientation = value;
        ChangeSize();
      }
    }

    #endregion

    #region overrides of default behaviour

    // We don't want any margin around us
    protected override Padding DefaultMargin => Padding.Empty;

    // Clean up parent references
    protected override void Dispose(bool disposing)
    {
      if (disposing)
        SetParent(null);
      base.Dispose(disposing);
    }

    // This seems to be needed for IDE support, as OnParentChanged does not seem
    // to fire if the control is dropped onto a surface for the first time
    protected override void OnHandleCreated(EventArgs e)
    {
      base.OnHandleCreated(e);
      ChangeSize();
    }

    // Make sure we don't inadvertantly paint anything
    protected override void OnPaint(PaintEventArgs e) { }
    protected override void OnPaintBackground(PaintEventArgs pevent) { }

    // If the parent changes, we need to:
    // A) Unsubscribe from the previous parent's Resize event, if applicable
    // B) Subscribe to the new parent's Resize event
    // C) Resize our control according to the new parent dimensions
    protected override void OnParentChanged(EventArgs e)
    {
      base.OnParentChanged(e);
      // Perform A+B
      SetParent(Parent);
      // Perform C
      ChangeSize();
    }

    // We don't really want to be resized, so deal with it
    protected override void OnResize(EventArgs e)
    {
      base.OnResize(e);
      ChangeSize();
    }

    #endregion

    #region private stuff

    // Make this a default handler signature with optional params, so that this can
    // directly subscribe to the parent resize event, but also be called without parameters
    private void ChangeSize(object sender = null, EventArgs e = null)
    {
      Rectangle client = Parent?.ClientRectangle ?? new Rectangle(0, 0, 10, 10);
      Size proposedSize = _orientation == Orientation.Horizontal
        ? new Size(client.Width, 0)
        : new Size(0, client.Height);
      if (!Size.Equals(proposedSize)) Size = proposedSize;
    }

    // Handles reparenting
    private Control boundParent;
    private void SetParent(Control parent)
    {
      if (boundParent != null)
        boundParent.Resize -= ChangeSize;
      boundParent = parent;
      if (boundParent != null)
        boundParent.Resize += ChangeSize;
    }

    #endregion
  }
}