Центрирование нескольких рядов элементов управления в FlowLayoutPanel - PullRequest
0 голосов
/ 05 февраля 2019

Я пытаюсь создать панель, которая будет содержать динамически добавленные элементы управления.Есть два предостережения:

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

Я видел пару предложенных решений для центрирования динамических элементов.элементы управления в форме и отклонил их по следующим причинам:

  • TableLayoutPanel - основная проблема, с которой я сталкиваюсь при использовании этого, - это события, когда элементы растут, и они должны перейти от сетки 3-2 к 2-4, так какTableLayoutPanel, похоже, плохо справляется с ними.
  • AutoSize FlowLayoutPanel, который может увеличиваться и уменьшаться внутри TableLayoutControl - моя главная проблема с этим решением состоит в том, что он центрирует только одну строку внутри формы, как только он переносится в новуюстрока, элементы начинают выравниваться по правой стороне.Я полагаю, что я могу динамически добавлять новые FlowLayoutPanels к новым строкам TableLayoutControl, но тогда у меня возникает проблема, аналогичная первой, когда мне нужно вручную перераспределять элементы между строками, если они растут / уменьшаются в размере.

Мне было интересно, если мне не хватает какой-то функциональности, которая может помочь мне обрабатывать события увеличения / сжатия без создания собственного варианта TableLayoutPanel?

Редактировать:
Ниже приведенчерновик функциональности:

  • A - два элемента по центру на панели
  • B - добавлен третий элемент, все три по центру
  • C - добавлен четвертый элемент, обернутый вновый ряд и по центру
  • D - Элементы увеличены, теперь переносятся на второй элемент, по центру

Draft

1 Ответ

0 голосов
/ 07 февраля 2019

Вот пример, который воспроизводит описанное вами поведение.
В нем используется TableLayoutPanel, в которой размещено несколько FlowLayoutPanel.

Одной важной деталью является привязка дочерних FlowLayoutPanels: их необходимо привязать к Top-Bottom : это заставляет панель располагаться в центре строки TableLayoutPanel.

Обратите внимание, что в конструкторе Form удаляется один из RowStyles.Это также очень важно: TLP (что является довольно эксцентричным парнем), даже если у вас есть только одна строка (или одна колонка, то же самое), сохранится 2 RowStyles.Второй стиль будет применен к первой добавляемой строке;только к первому, а не к другим: это может испортить макет.

Еще одна аномалия, она не предоставляет метод для удаления строки, поэтому я ее создал.Это функционально, но просто и требует расширения, включая дальнейшие проверки.

См. Графический пример с текущими функциями.Если вам нужна помощь в реализации чего-то еще, оставьте комментарий.


Чтобы построить это, добавьте в форму следующие элементы управления (здесь они называются FLPTest1):

  1. Добавьте одну панель, установите Dock.Bottom.Щелкните правой кнопкой мыши и SendToBack(),
  2. Добавьте TableLayoutPanel (здесь, называемый tlp1), установите:
    • AutoScroll = true, AutoSize = true,
    • AutoSizeMode = GrowAndShrink, Dock.Fill
    • Сохранить 1 столбец, установить автоматический размер и одну строку, установить автоматический размер
  3. Добавить FlowLayoutPanel (здесь, называемый flp1), расположенный внутри TableLayoutPanel.На самом деле в этом нет необходимости, просто для этого примера кода
    • Установите его привязку на Top, Bottom <= это !important, без него раскладка будет работать некорректно: она позволяет центрироватьFLP внутри строки TLP,
    • AutoSize = true, AutoSizeMode = GrowAndShrink
  4. Добавить кнопку (называемую btnAddControl)
  5. Добавить вторую кнопку (называемую btnRemoveControl)
  6. Добавить флажок (называемый chkRandom)
  7. Вставитькод здесь внутри файла кода формы

TableLayoutPanel Flow

using System.Drawing;
using System.Linq;
using System.Windows.Forms;


public partial class TLPTest1 : Form
{
    public TLPTest1()
    {
        InitializeComponent();
        this.tlp1.RowStyles.RemoveAt(1);
    }

    private void TLPTest1_Load(object sender, EventArgs e)
    {
        PictureBox pBox = new PictureBox() {
            Anchor = AnchorStyles.None,
            BackColor = Color.Orange,
            MinimumSize = new Size(125, 125),
            Size = new Size(125, 125),
        };
        this.flp1.Controls.Add(pBox);
        this.tlp1.Controls.Add(flp1);
    }

    Random rnd = new Random();
    Size[] sizes = new Size[] { new Size(75, 75), new Size(100, 100), new Size(125, 125)};
    Color[] colors = new Color[] { Color.Red, Color.LightGreen, Color.YellowGreen, Color.SteelBlue };
    Control selectedObject = null;

    private void btnAddControl_Click(object sender, EventArgs e)
    {
        Size size = new Size(125, 125);
        if (this.chkRandom.Checked)
            size = sizes[rnd.Next(sizes.Length)];

        PictureBox pBox = new PictureBox() {
            Anchor = AnchorStyles.None,
            BackColor = colors[rnd.Next(colors.Length)],
            MinimumSize = size,
            Size = size
        };

        bool drawborder = false;
        pBox.MouseEnter += (s, evt) => { drawborder = true;  pBox.Invalidate(); };
        pBox.MouseLeave += (s, evt) => { drawborder = false; pBox.Invalidate(); };
        pBox.MouseDown += (s, evt) => { selectedObject = pBox;  pBox.Invalidate(); };
        pBox.Paint += (s, evt) => { if (drawborder) {
                ControlPaint.DrawBorder(evt.Graphics, pBox.ClientRectangle, 
                                        Color.White, ButtonBorderStyle.Solid);
            }
        };

        var ctl = this.tlp1.GetControlFromPosition(0, this.tlp1.RowCount - 1);
        int overallWith = ctl.Controls.OfType<Control>().Sum(c => c.Width + c.Margin.Left + c.Margin.Right);
        overallWith += (ctl.Margin.Right + ctl.Margin.Left);
        if ((overallWith + pBox.Size.Width + pBox.Margin.Left + pBox.Margin.Right) >= this.tlp1.Width)
        {
            var flp = new FlowLayoutPanel() {
                Anchor = AnchorStyles.Top | AnchorStyles.Bottom,
                AutoSize = true,
                AutoSizeMode = AutoSizeMode.GrowAndShrink,
            };
            flp.Controls.Add(pBox);

            this.tlp1.SuspendLayout();
            this.tlp1.RowCount += 1;
            this.tlp1.Controls.Add(flp, 0, this.tlp1.RowCount - 1);
            this.tlp1.ResumeLayout(true);
        }
        else
        {
            ctl.Controls.Add(pBox);
        }
    }

    private void btnRemoveControl_Click(object sender, EventArgs e)
    {
        if (selectedObject is null) return;
        Control parent = selectedObject.Parent;
        selectedObject.Dispose();
        if (parent?.Controls.Count == 0)
        {
            TLPRemoveRow(this.tlp1, parent);
            parent.Dispose();
        }
    }

    private void TLPRemoveRow(TableLayoutPanel tlp, Control control)
    {
        int ctlPosition = this.tlp1.GetRow(control);
        if (ctlPosition < this.tlp1.RowCount - 1)
        {
            for (int i = ctlPosition; i < this.tlp1.RowCount - 1; i++)
            {
                tlp.SetRow(tlp.GetControlFromPosition(0, i + 1), i);
            }
        }
        tlp.RowCount -= 1;
    }
}
...