UserControl не отображается в FlowLayoutPanel при изменении док-станции

Когда я добавляю свои UserControls в FlowLayoutPanel, они отображаются правильно. Когда я изменяю свойства Dock или Anchor в UserControls перед их добавлением, они все равно добавляются, но не отображаются.

Согласно «Как: привязать и закрепить дочерние элементы управления», это должно быть возможный.

  • Я могу сказать, что элементы управления добавлены (несмотря на то, что они не нарисованы), потому что добавление достаточного количества из них вызывает появление вертикальной полосы прокрутки.
  • Установка для свойства «Dock» UserControls значения «Left» или «None» приведет к их рендерингу, но ни один из других параметров.
  • Установка свойства "Anchor" в UserControls на любое значение, кроме Top | Слева не отображает.
  • Установка док-станции до или после добавления элемента управления не имеет значения (Добавить, Док против дока, Добавить).
  • 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;
}

person user664939    schedule 15.09.2011    source источник
comment
Док чего вы меняете?   -  person Tigran    schedule 16.09.2011
comment
@Tigran: Я отредактировал пост для уточнения. Я меняю док в UserControls, который добавляю в FlowLayoutPanel.   -  person user664939    schedule 16.09.2011
comment
Как вы можете установить стыковку / заливку для пользовательских элементов управления перед их добавлением?   -  person Hans Passant    schedule 16.09.2011
comment
Вы добавляете их в режиме разработки или во время выполнения (через код)?   -  person Arun    schedule 16.09.2011
comment
@Hans Passant: обновлен фрагмент кода, чтобы ответить на ваш комментарий.   -  person user664939    schedule 16.09.2011
comment
@Arun: я добавляю их во время выполнения. Я редактировал в коде.   -  person user664939    schedule 16.09.2011
comment
В примере MSDN в ссылке для FlowLayoutPanel задана фиксированная ширина. Вы сказали, что у вас есть свой DockStyle.Fill. Вы бы хотели это изменить?   -  person Arun    schedule 16.09.2011
comment
Вы уверены, что элементы управления не будут отображаться ИЛИ не отображается только содержимое. Я имею в виду, уверены ли вы, что ваш UserControl правильно работает при изменении размера? Иногда элементы управления в вашем UserControl перемещаются в какое-то скрытое место во время изменения размера.   -  person rudolf_franek    schedule 16.09.2011
comment
Я думаю, что размер UserControl каким-то образом становится 0,0, когда для Dock установлено значение DockStyle.Fill. Я думаю, это может быть из-за того, что UserControl не имеет собственного размера. Я сам здесь очень запутался.   -  person binki    schedule 12.06.2014
comment
Это не имеет ничего общего с вашим UserControl. Это также происходит, если вы используете стандартный элемент управления Panel, и поведение по-прежнему сохраняется с .net461 в VS2015.   -  person takrl    schedule 28.04.2016


Ответы (2)


попробуйте использовать функции SuspendLayout и Resumelayout для элементов управления, прежде чем вносить какие-либо изменения, требующие визуализации для правильного просмотра.

Вы могли увидеть код из Designer.cs для этого конкретного элемента управления.

Синтаксис

control.SuspendLayout();
{Your code for designer amendments}
control.resumeaLayout();
person XYZ    schedule 28.11.2014

Я думаю, что, возможно, нашел обходной путь (читай: грязный трюк) ... этот ответ помог мне правильно указать направление. Вот отрывок из статьи MS, на которую вы также сделали ссылку:

Для вертикальных направлений потока элемент управления FlowLayoutPanel вычисляет ширину подразумеваемого столбца на основе самого широкого дочернего элемента управления в столбце. Все остальные элементы управления в этом столбце со свойствами привязки или закрепления выровнены или растянуты, чтобы соответствовать этому предполагаемому столбцу.

Подобным образом поведение работает для горизонтальных направлений потока. Элемент управления FlowLayoutPanel вычисляет высоту подразумеваемой строки на основе самого высокого дочернего элемента управления в строке, и все закрепленные или закрепленные дочерние элементы управления в этой строке выравниваются или имеют размер, чтобы соответствовать предполагаемой строке.

На этой странице конкретно не упоминается, что вы не можете закрепить / закрепить самый высокий / самый широкий элемент управления. Но поскольку этот элемент управления определяет поведение макета FlowLayoutPanel и, таким образом, влияет на способ отображения всех других элементов управления, родственных друг другу, вполне возможно, что Dock и Anchor не работают должным образом для этого «главного элемента управления». Хотя я не могу найти никакой официальной документации по этому поводу, я считаю, что это так.

Итак, какие у нас есть варианты? Во время выполнения мы могли бы добавить панель управления высотой 0 и шириной клиентской области FlowLayoutPanel до того, как вы добавите свой пользовательский элемент управления. Вы даже можете установить для этой панели значение false. Подписка на некоторые события Resize / Layout FlowLayoutPanel, чтобы сохранить размер этой панели, поможет. Но это не очень хорошо во время разработки. События не срабатывают, и поэтому вы не можете спроектировать поверхность так, как вы хотите, чтобы она выглядела.

Я бы предпочел решение, которое работает и во время разработки. Итак, вот попытка невидимого элемента управления, который я собрал, чтобы исправить изменение размера элементов управления до нулевой ширины, если нет другого элемента управления. Отбрасывание этого элемента в качестве первого элемента управления на FlowLayoutPanel во время разработки, по-видимому, обеспечивает желаемый эффект, и любой элемент управления, впоследствии помещенный в FlowLayoutPanel, может быть закреплен справа без уменьшения ширины до нуля. Единственная проблема заключается в том, что когда этот невидимый элемент управления присутствует, кажется, я больше не могу его удалить через IDE. Вероятно, для этого потребуется особая обработка с использованием ControlDesigner. Однако его все еще можно удалить в коде конструктора формы.

Этот элемент управления, помещенный в FlowLayoutPanel, будет прослушивать события изменения размера своего родительского элемента управления и изменять свой размер в соответствии с 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
  }
}
person takrl    schedule 28.04.2016