JayK
JayK

Reputation: 3141

How to avoid having the z-order of Controls changed when showing and hiding them?

I have got a Form with some Controls (Panels, Group Boxes etc.) on it which all have control.Dock = DockStyle.Top set. Based on the selected value of a ComboBox on the Form only some of these Panels should be visible at the same time (because the hidden ones don't apply for the selected option). The docking is to make the UI appear more compact.

The Visible properties of those Panels are changed whenever the ComboBox selection changes and on the Form's Shown event (because not all Panels should be visible when the Form is shown for the first time and the ComboBox selection has not yet changed).

Now, the problem is, that when I close the Form (as it is a modal dialog, it is not destroyed), reopen it later and change the ComboBox selection the display order of the Panels at the top of the Form has changed. It does not happen until the Form was closed one time. I know that the display order of docked Controls is linked to the order of these Controls in the parent control's ControlCollection. This also determines the z-Order of the Controls, hence the question's title.

What causes the Controls order to change and how to avoid it?

Upvotes: 3

Views: 883

Answers (1)

JayK
JayK

Reputation: 3141

After more debugging I found out that the reordering is related to Handle creation.

When the Form is first opened, all Panels are visible (as I didn't change that at design time) and all Handles are created immediately, before some are hidden by the Form.Shown event handler. When the Form is closed, the handles are lost. However, if the Form is shown for the second time, only the handles of the Panels that have been visible when the Form was closed are recreated immediately. Each handle is created once the Control becomes visible (as MSDN points out) but apparently now the order of showing the Controls is important because the Controls can be moved in the parent's ControlCollection upon handle creation.

It turned out that when the Form was shown the second time, before showing a certain Panel (here PanelToBecomeVisible) the Control order was:

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

where v means visible and h that IsHandleCreated is true. After PanelToBecomeVisible.Visible = True the ControlCollection looks like this:

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

And if Panel2 becomes visible later, it will subsequently have swapped positions with PanelToBecomeVisible.

Thus, one solution is to make sure all handles are created early even if the Panels are not visible yet. This can be achieved by accessing the Handle property of every Control in question like this, e. g.:

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

Upvotes: 5

Related Questions