Страницы

Поиск по вопросам

пятница, 26 октября 2018 г.

WinForms: GroupBox со свойствами DockStyle.Left, AutoSize=true уменьшается в размерах игнорируя минимальную ширину содержащихся компонентов

Существует очередь компонентов которая должна содержаться на форме. На очередь компонентов повлиять нельзя. Каждый из компонентов, в свою очередь, может так-же являться контейнером со своими контролами и все они должны быть корректно отрисованы.
Для примера
Предположим что на форме у нас существует один GroupBox, а в GroupBox последовательно помещены компоненты Panel(){Dock=DockStyle.Top}, Splitter(){Dock=DockStyle.Top}, new Panel(){Dock=DockStyle.Top}, new Panel(){Dock=DockStyle.Fill}
Для всех Panel устанавливаем свойства MinimumSize = new Size(200, 40)
Получаем вот такой результат:

Для GroupBox устанавливаем свойства MinimumSize = new Size(30, 30), AutoSize = true, Dock = DockStyle.Left
Наблюдаем картину:

GroupBox проигнорировал минимальную ширину компонентов Panel и схлопнулся до собственного минимального размера.
Вопросы:
1) Почему так происходит?
2) Как добиться того что-бы GroupBox не игнорировал минимальную ширину компонента TextBox в такой ситуации и при этом оставить работоспособный Splitter между Panel?
p.s. По условию необходимо формировать ряд групп (между которыми так-же может быть сплиттер) которые будут последовательно находиться по горизонтали. Поля в группе должны быть расположены последовательно по вертикали.
Буду рад любым подсказкам


Ответ

К сожалению, вы нашли еще одну "особенность" форм. Пожалуй WinForms - тот редкий случай, где наличие множественного наследования в C# могло бы, чисто теоретически, помочь избежать некоторого количества граблей. Тут еще один замечательный пример "особенностей" контейнеров WinForms, там же есть линк на исходники.
Теперь по делу. Просто настройками это можно исправить, но не слишком удобно, особенно если не хочется руками позиционировать контролы. Если это не критично. см соседний ответ.
Дело в том, что когда вы привязываете контрол через свойство Dock, то дочерний котрол подгоняет свои размеры под родительский, но строго после того, как родительский контрол изменил свои размеры. Иными словами, минимальный размер вашего TextBox, проверяется после того, как GroupBox схлопнулся до своего минимального размера. Вообще, там довольно мудреная связь между свойствами, отвечающими за размеры, посмотрите ответ по ссылке выше, что бы не дублировать.
Чтобы получить:
По условию необходимо формировать группы полей которые будут последовательно находиться по горизонтали. Поля в группе должны быть расположены последовательно по вертикали.
и при этом иметь нормальную картинку обойдя все "особенности", необходимо:
За основу возьмем Panel, можно и форму, разница, в данном случае, не велика. Так как контент динамический, то существует ненулевая вероятность. что он не поместится на панели целиком, поэтому включаем у панели AutoScroll = true Добавляем на Panel FlowLayoutPanel, и задаем свойство Location = 0,0. Важно: свойство Dock = None, иначе не будет работать как задумано. AutoSize = true, AutoSizeMode = GrowAndShrink, WrapContents = false, FlowDirection = LeftRight На FlowLayoutPanel добавляем GroupBox-ы, количество по желанию, со свойствами AutoSize = true, AutoSizeMode = GrowAndShrink, Dock = None В GroupBox добавляем FlowLayoutPanel со свойствами AutoSize = true, AutoSizeMode = GrowAndShrink, WrapContents = false, Dock = Fill, FlowDirection = TopDown. На FlowLayoutPanel GroupBox-а кидаем через один Label-ы (подписи к полям) и TextBox-ы, тех размеров, которые нужны для отображения данных.
В результате, имеем размещение элементов сверху вниз внутри GroupBox и GroupBox-ы, размещенные слева направо. Все элементы видны в полный размер. Если не уместились, появятся нужные скролы и все можно будет увидеть. Единственный недостаток - при вертикальном скроле, будут прокручиваться все элементы сразу, что не очень красиво. Но я пока не придумал как красиво сделать индивидуальный вертикальный скрол у каждого GroupBox

Альтернативное решение со сплиттером
Особенность работы со сплиттером, заключается в том, что хотя бы один элемент из двух, между которыми находится сплиттер, не должен иметь значений свойств AutoSize = true и Dock = DockStyle.Fill. Если у обоих элементов эти свойства имеют такие значения, то сплиттер попросту не работает.
В таком случае решением будет следующая компоновка контрола:
За основу возьмем Panel(0) На Panel(0) добавляем GroupBox со свойством AutoSize = false. Если этот GroupBox последний - Dock = Fill, иначе - Dock = Left
2.1. В GroupBox добавляем Panel(1) со свойствами AutoSize = false, AutoScroll = true. Если в этом GroupBox еще требуются сплиттеры Dock = Up, иначе Dock = Fill и идем в пункт 2.3.
2.2. В GroupBox добавляем Splitter со свойством Dock = Up
2.3. На Panel(1) добавляем через один Label-ы (подписи к полям) и TextBox-ы, со свойствами AutoSize = false, Dock = Up Если GroupBox единственный - закончили, иначе - на Panel(0) добавляем Splitter со свойством Dock = Left и возвращаемся в пункт 2.
Все сплиттеры работают, и у элементов групбоксов работает вертикальный скролл, но при этом не возможно ни какими средствами задействовать общий вертикальный скрол колонок и общий горизонтальный скрол. Групповой скрол может появиться, если у последних элементов заменить Dock = Fill на Dock = Up, но при этом перестают работать сплиттеры. Начальную ширину групбоксов нужно вычислять заранее, например как отношение ширины панели к количеству групбоксов.
Больше действующих вариантов без наследования и переопределения поведения контролов по-умолчанию, найти не удалось. Возможно что-то могут предложить платные библиотеки компонентов, вроде SyncFusion и DevExpress, но больно уж специфическая задача, так что я бы на это не рассчитывал особо.

Комментариев нет:

Отправить комментарий