Reputation: 3141
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
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