Windows Develop Bookmark and Share   
 index > Windows Forms Designer > Understanding ZOrder
 

Understanding ZOrder

After searching the KB and this forum, I haven't found a question dealing with this aspect of zorder, so maybe the question needs to be asked.

Can someone explain the logic that determines true zorder for controls within a form or parent control?  Through experimentation I'm getting intimations of how it works, but I haven't cracked the essence.

If the controls you add to a container are all visible at the time you add them, zorder works exactly as documented in all the easily-found places.  (To simplify the discussion, I'm assuming you add them all in one call to AddRange.)

But suppose for the sake of illustration that the child controls are all INVISIBLE at the time you add them and you subsequently make them visible in (for the sake of illustration) random order.

The zorder is no longer what you expect.  It depends in some fashion on the order in which you make the controls visible, yet it is not that order, exactly, either.  This does not seem to be an artifact of confused Refresh()es.  If you iterate over the Controls and display their hashcodes, you see that the internal order of controls is changing as you show some and leave others hidden.  The internal order appears to match the zorder visible on the screen, although the documentation leaves some ambiguity about that.

Once all the controls have become visible, you can reorder them with SetChildIndex(p,c) and the zorder thus established seems to persist through all future showing and hiding.  But you can't use SetChildIndex(p,c) to solve the problem for a particular child until AFTER that child has been shown.  And it must really appear on the screen, too -- it isn't enough to show the child if the parent is invisible or obscured by another object.  It looks like the zorder doesn't get pinned until is written to the screen.

Is this how it's supposed to work?  Is it old news to old hands?  Is there somewhere where the internal logic is discussed?

The reason it matters is that when developing apps that sequentially or interactively overlay commentary, highlighting, pointers, etc., it is desirable to be able to predict (or even control!) the zordering of elements without needing to make them all visible before their zorder becomes reliable.  Perhaps it is reliable now, but in a fashion I have not yet worked out.

MigrationUser 1  Monday, June 28, 2004 10:47 PM
Here's a minimal demonstration of the problem for anyone who's curious.  Would be nice to find out whether this is a Windows Forms bug or a well-known legacy behavior.

using System;
using System.Windows.Forms;
using System.Drawing;

public class ZForm : Form {
    Panel thePanel = new Panel();
    Button theButton = new Button();

//////////////////////
    static void Main() {
        Application.Run(new ZForm(new Size(316, 348)));
    }

//////////////////////
    public ZForm( Size s ) {
        this.ClientSize = s;
        thePanel.Bounds = new Rectangle(0, 0, 316, 316);
        this.Controls.Add(thePanel);
        theButton.Location = new Point(8, 324);
        this.Controls.Add(theButton);
        this.theButton.Click += new System.EventHandler(this.theButton_Click);
    }

//////////////////////
    void theButton_Click(object sender, System.EventArgs e) {
        Point tLoc = new Point(16, 196);
        Size tSize = new Size(128, 128);
        int ix;

        // Ten textboxes and an arbitrary ordering
        TextBox[] theList = new TextBox[10];
        int[] theShowOrder = {2, 3, 7, 6, 9, 1, 0, 5, 8, 4};

        // Make a neat stack of invisible textboxes
        for( ix=0; ix <10; ix++) {
            tLoc.Offset(16, -16);
            theList[ix] = makeTextBox(tLoc, tSize, ix);
        }

        // Add the whole stack to the panel, but still invisible
        thePanel.Controls.Clear();
        thePanel.Controls.AddRange(theList);

        // Redundant and futile attempt to assure zorder
        for( ix=0; ix <10; ix++) {
            thePanel.Controls.SetChildIndex(theList[ix], ix);
        }

        // Show controls in arbitrary order
        foreach( int jx in theShowOrder) {
            (theList[jx]).Show();
        }

        // Re-layer controls to intended zorder -- now it works
        MessageBox.Show(this, "Before 2nd SetChildIX Loop");
        for( ix=0; ix <10; ix++) {
            thePanel.Controls.SetChildIndex(theList[ix], ix);
        }
    }

//////////////////////
    TextBox makeTextBox( Point p, Size s, int ix ) {
        TextBox t = new TextBox();
        t.Location = p;
        t.Size = s;
        t.Text = ix.ToString();
        t.Multiline = true;
        t.Visible = false;
        return t;
    }
}
MigrationUser 1  Tuesday, June 29, 2004 12:51 PM

You can use google to search for other answers

Custom Search

More Threads

• Binding data to the custom DataGridView
• UPLOADING A PICTURE
• Unable to open form designer...
• Copy Form Design to another Form or Application?
• Tree View Help Required
• Problem in Form Inheritance if the Base form use some shared property of a class
• How to retrieve a specific treeview node?
• how to host different controls in the same column in DataGridView control
• ListView SelectedIndexChanged fired more than once
• UI framework with Base form and sizes of controls in winforms