Как настроить TableLayoutPanel для переноса содержимого по росту и весу? (Динамически) - PullRequest
0 голосов
/ 19 марта 2020

Я создал Form, который я собираюсь использовать в качестве всплывающего окна. Мне нужно, чтобы это всплывающее окно содержало заголовок, индикатор выполнения и текст в процентах.

Поэтому для этой цели я решил использовать TableLayoutPanel в качестве элемента управления в моей форме.

Существует код, который создает все эти представления динамически. Для проверки сейчас я использую lable вместо реальной реализации прогрессбара.

public partial class TestFormDeleteIt : Form
    {
        public TestFormDeleteIt()
        {
            InitializeComponent();

            AutoSize = true;

            var flp = CreateTableLayoutPanel();
            Controls.Add(flp);
        }

        private Control CreateTableLayoutPanel()
        {
            // TableLayoutPanel Initialization
            var panel = new TableLayoutPanel
            {
                ColumnCount = 2,
                RowCount = 2,
                Dock = DockStyle.Fill
            };

            //Adjust column size in percentage
            panel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 70F));
            panel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 30F));

            //Adjust row size in percentage
            panel.RowStyles.Add(new RowStyle(SizeType.Percent, 50F));
            panel.RowStyles.Add(new RowStyle(SizeType.Percent, 50F));

            //Fill content
            panel.Controls.Add(
                new Label()
                {
                    Text = "state",
                    Dock = DockStyle.Fill
                }, 
                /*column*/ 0, /*row*/ 0);

            panel.Controls.Add(
                new Label()
                {
                    Text = "ProgressBar",
                    Dock = DockStyle.Fill
                },
                /*column*/ 0, /*row*/ 1);

            panel.Controls.Add(
                new Label()
                {
                    Text = "100%",
                    Dock = DockStyle.Fill
                }, 
                /*column*/ 1, /*row*/ 1);

            return panel;
        }
    }

Итак, как вы можете видеть, я создаю TableLayoutPanel, разделенную на строки и столбцы, и для каждого представления, которое он содержит, я устанавливаю Dock = DockStyle.Fill , потому что я не хочу использовать размер фиксированного кода.

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

Но на самом деле я получаю такой результат:

enter image description here

Root форма не переносит содержимое, похоже, что она имеет фиксированный размер, и в таблице размечаются попытки заполнить этот root размер формы, но я установил AutoSize = true;, но это не влияет ...

Что я делаю не так?

РЕДАКТИРОВАТЬ

Спасибо, @ Джими теперь выглядит намного лучше

enter image description here

Я также добавил

MinimumSize = new System.Drawing.Size(600, Height)

в TLP, но вопрос - как вы можете видеть, что каждый ряд имеет как минимальную высоту. И это похоже на пространство между каждым рядом. Почему это происходит?

EDIT2

Я хотел бы заметить, что если я изменю это

            panel.Controls.Add(
                new Label()
                {
                    Text = "state",
                    Dock = DockStyle.Fill
                },
                /*column*/ 0, /*row*/ 0);

на это

var label1 = new Label()
            {
                Text = "state",
                Dock = DockStyle.Fill
            };

            panel.SetRow(label1, 0);
            panel.SetColumn(label1, 0);

это не работает ... Что я делаю не так?

и вот мой код сейчас

public partial class TestFormDeleteIt : Form
    {
        public TestFormDeleteIt()
        {
            InitializeComponent();

            AutoSize = true;
            AutoSizeMode = AutoSizeMode.GrowAndShrink;
            MinimumSize = new System.Drawing.Size(200, 0);

            var flp = CreateTableLayoutPanel();
            Controls.Add(flp);
        }

        private TableLayoutPanel CreateTableLayoutPanel()
        {
            // TableLayoutPanel Initialization
            var panel = new TableLayoutPanel
            {
                ColumnCount = 2,
                RowCount = 2,
                Dock = DockStyle.Fill
            };

            //Adjust column size in percentage
            panel.ColumnStyles.Clear();
            panel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 90F));
            panel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 10F));

            //Adjust row size in percentage
            panel.RowStyles.Clear();
            panel.RowStyles.Add(new RowStyle(SizeType.Percent, 50F));
            panel.RowStyles.Add(new RowStyle(SizeType.Percent, 50F));

            //Fill content
            panel.Controls.Add(
                new Label()
                {
                    Text = "state",
                    Dock = DockStyle.Fill
                },
                /*column*/ 0, /*row*/ 0);

            panel.Controls.Add(
                CreateProgressBar(),
                /*column*/ 0, /*row*/ 1);

            panel.Controls.Add(
                new Label()
                {
                    Text = "100%",
                    Dock = DockStyle.Fill
                }, 
                /*column*/ 1, /*row*/ 1);

            panel.AutoSizeMode = AutoSizeMode.GrowAndShrink;
            panel.AutoSize = true;

            return panel;
        }

        private Control CreateProgressBar() => new ProgressBar()
        {
            Visible = true,
            Dock = DockStyle.Top
        };
    }

Проблема в том, что даже если я установлю stati c ширина как 200 -> MinimumSize = new System.Drawing.Size(200, 0) в моей форме, когда я открываю ее, я вижу, что она занимает примерно 1000 ...

enter image description here

Почему это случилось?

1 Ответ

1 голос
/ 19 марта 2020

Сценарий :

  • Форма голой кости, без указания c размеров. Нет дочерних элементов управления.
  • A TableLayoutPanel создается с нуля во время выполнения. Без указания c размеры
    • Две строки и два столбца создаются с режимом размера, установленным в процентах
    • Три элемента управления создаются с нуля и добавляются к трем ячейкам TableLayoutPanel
      TableLayoutPanel должен изменить свой размер до нового содержимого, которое не имеет заданного размера c (кроме размера по умолчанию, примененного к элементам управления Windows Forms), без сжатия из-за отсутствия новых дочерних элементов управления
  • Форма после добавления TableLayoutPanel в свою коллекцию Controls должна автоматически изменять свой размер до размера его (только) дочернего элемента управления, сохраняя недавно установленную минимальную ширину, но не минимальную или максимальная высота (поэтому она может расширяться по вертикали, если необходимо, но не по горизонтали)
  • Наконец, элемент TableLayoutPanel с автоматическими размерами должен быть закреплен внутри контейнера формы с автоматическими размерами, и все части должны взаимодействовать для создания ожидаемого Макет

Как действовать :

Последовательность операций будут четко определять конечный результат.

  1. Форма инициализируется: ее конструктор вызывает стандартный метод InitializeComponent (). Здесь нет дочерних элементов управления, поэтому на самом деле нет ничего для разметки. Форма просто установит размер, определенный в конструкторе.
  2. Теперь мы инструктируем Форму для Авторазмера для ее содержимого, а также для того, чтобы ей разрешалось увеличивать и уменьшать ее Размер для выполнения sh этой задачи. Форма на самом деле ничего не делает прямо сейчас, так как она не может выполнить свой макет в это время (если явно не указано иное, используя метод PerformLayout())
  3. Мы устанавливаем минимальный размер, ограничивая его ширину, но не его высота (настройка MinimumSize = new Size(200, 0), мы определяем минимальную ширину, но измерение высоты можно свободно увеличивать и уменьшать, здесь - установка 0 в качестве значения означает без ограничений ).
  4. Теперь TableLayoutPanel и его дочерние элементы управления создаются с использованием размеров по умолчанию (Windows При создании элементов управления Forms используется размер по умолчанию). Ярлыки автоматически изменят размер до размера их текста: это поведение по умолчанию.
  5. После того, как все дочерние элементы управления добавлены в TLP, TLP получает указание самостоятельно изменить размер, указав также, что он может увеличиваться и уменьшаться для выполнения макета. 6 TableLayoutPanel добавляется в контейнер Form. Теперь, когда элемент Control добавлен в коллекцию Controls, внутренний метод дает команду ContainerControl на SuspendLayout(), расположите новый элемент управления и ResumeLayou() (без выполнения макета дочерние элементы управления, поскольку это только что произошло): в этот момент форма, получившая указание автоматически изменить размер своего содержимого, вычислит PreferredSize, а затем автоматически изменит свой размер на новое содержимое.
  6. TableLayoutPanel теперь установлен в Dock для родительского контейнера. Контейнер уже автоматически настроен на размер TableLayoutPanel, поэтому TLP просто фиксирует свои привязки к текущему размеру формы.

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

Extra :

► Явные таблицы TableLayoutPanel SetColumn () и SetRow () вызываются явным образом. Причина частично объясняется в разделе «Примечания» двух методов:

Этот метод повторно применяет макет таблицы ко всем элементам управления в TableLayoutPanel.

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

Некоторые примечания по этому вопросу можно найти здесь:
Этот код (другой язык, но простой для чтения) может быть легко протестирован для воспроизведения проблемы
Dynami c Элементы управления TableLayoutPanel поддерживают ширину границы

ColumnStyles и RowStyles очищаются и добавляются новые стили:
- Исходный код фактически добавляет новые стили, не удаляя существующие, используемые по умолчанию: в некоторых ситуациях это может привести к возникновению проблемы с макетом. Некоторые замечания по этому вопросу здесь:

Удаление строки внутри TableLayoutPanel создает проблему макета
Центрирование нескольких строк элементов управления в FlowLayoutPanel


public partial class TestFormDeleteIt : Form
{
    protected internal ProgressBar pBar = null;
    protected internal Label lbl2 = null;

    public TestFormDeleteIt()
    {
        InitializeComponent();

        this.AutoSize = true;
        this.AutoSizeMode = AutoSizeMode.GrowAndShrink;
        this.MinimumSize = new Size(200, 0);

        var tlp = CreateTableLayoutPanel();

        tlp.AutoSizeMode = AutoSizeMode.GrowAndShrink;
        tlp.AutoSize = true;

        this.Controls.Add(tlp);
        tlp.Dock = DockStyle.Fill;
    }

    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        Task.Run(() => UpdateProgress());
    }

    private TableLayoutPanel CreateTableLayoutPanel()
    {
        var panel = new TableLayoutPanel { ColumnCount = 2, RowCount = 2,
            CellBorderStyle = TableLayoutPanelCellBorderStyle.Single
        };
        panel.ColumnStyles.Clear();
        panel.RowStyles.Clear();

        panel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 70F));
        panel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 30F));

        panel.RowStyles.Add(new RowStyle(SizeType.Percent, 50F));
        panel.RowStyles.Add(new RowStyle(SizeType.Percent, 50F));

        var lbl1 = new Label() { Text = "state", Dock = DockStyle.Fill };
        panel.Controls.Add(lbl1);
        panel.SetColumn(lbl1, 0);
        panel.SetRow(lbl1, 0);

        pBar = new ProgressBar() { Dock = DockStyle.Top };
        panel.Controls.Add(pBar);
        panel.SetColumn(pBar, 0);
        panel.SetRow(pBar, 1);

        lbl2 = new Label() { Text = "0%", Dock = DockStyle.Fill };
        panel.Controls.Add(lbl2);
        panel.SetColumn(lbl2, 1);
        panel.SetRow(lbl2, 1);

        return panel;
    }

    private async Task UpdateProgress()
    {
        for (int i = 1; i <= 100; i++) {
            BeginInvoke(new Action(() => {
                pBar.Value = i;
                lbl2.Text = (i / 100.0).ToString("P");
            }));
            await Task.Delay(50);
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...