Как избежать изменения z-порядка элементов управления при их отображении и скрытии?

#.net #winforms #show-hide #visible #z-order

#.net #winforms #показать-скрыть #видимый #z-порядок

Вопрос:

У меня есть форма с некоторыми элементами управления (панелями, групповыми блоками и т.д.) На ней, Которые все control.Dock = DockStyle.Top установлены. В зависимости от выбранного значения выпадающего списка в форме одновременно должны быть видны только некоторые из этих панелей (поскольку скрытые панели не применяются к выбранной опции). Стыковка предназначена для того, чтобы пользовательский интерфейс выглядел более компактным.

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

Теперь проблема в том, что когда я закрываю форму (поскольку это модальное диалоговое окно, оно не уничтожается), повторно открываю ее позже и меняю поле со списком, порядок отображения панелей в верхней части формы изменился. Этого не происходит, пока форма не была закрыта один раз. Я знаю, что порядок отображения закрепленных элементов управления связан с порядком этих элементов управления в ControlCollection родительского элемента управления. Это также определяет z-порядок элементов управления, отсюда и название вопроса.

Что вызывает изменение порядка элементов управления и как этого избежать?

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

1. Из описания невозможно догадаться. Отправьте небольшой проект repro с этой проблемой в службу общего доступа к файлам или вставьте bin.

2. @HansPassant Ну, на самом деле я тем временем нашел ответ, но пока не могу его опубликовать (потому что мой рейтинг репутации слишком низок). Вы имеете в виду, что я плохо описал проблему и должен ее перефразировать, или вам просто нужен какой-то код, чтобы разобраться в этом самостоятельно?

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

4. Ну, может быть. Вам действительно нужно опубликовать ответ. Я надеюсь, это очевидно.

5. Это из-за 8-часовой задержки для новых пользователей. Я собираюсь ввести свое решение завтра вечером.

Ответ №1:

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

При первом открытии формы видны все панели (поскольку я не менял это во время разработки), и все дескрипторы создаются немедленно, прежде чем некоторые из них будут скрыты Form.Shown обработчиком событий. Когда форма закрыта, дескрипторы теряются. Однако, если Форма отображается во второй раз, немедленно воссоздаются только дескрипторы панелей, которые были видны при закрытии формы. Каждый дескриптор создается, как только элемент управления становится видимым (как указывает MSDN), но, по-видимому, теперь порядок отображения элементов управления важен, потому что элементы управления могут быть перемещены в родительской ControlCollection при создании дескриптора.

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

 0    Panel1
1  h InitiallyVisibleButLaterHiddenPanel
2    Panel2
3    PanelToBecomeVisible
4 vh AlwaysVisibleTopMostPanel
  

где v означает visible, а h, которое IsHandleCreated, равно true. После
PanelToBecomeVisible.Visible = True ControlCollection выглядит следующим образом
это:

 0    Panel1
1  h InitiallyVisibleButLaterHiddenPanel
2 vh PanelToBecomeVisible
3    Panel2
4 vh AlwaysVisibleTopMostPanel
  

И если Panel2 станет видимым позже, впоследствии он поменяется местами
позиции с PanelToBecomeVisible.

Таким образом, одним из решений является обеспечение того, чтобы все дескрипторы были созданы заранее, даже если панели еще не видны. Этого можно достичь, обратившись к Handle свойству каждого рассматриваемого элемента управления вот так, например.:

 Private Sub Form_Shown(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Shown
    Dim h As IntPtr
    For Each ctrl As Control In ParentControl.Controls
        h = ctrl.Handle
    Next
End Sub