locked
Z order with MDI RRS feed

  • Question

  • Ive got a MDI parent with numerous MDI children, wondering if I can modify the Z order programmatically of the MDI children.
    Tuesday, June 21, 2005 11:04 PM

Answers

  • If you want to bring a particular child to the front, call its BringToFront() method.  If you want to arrange the children in a particular order, work through the children in reverse order and call BringToFront() on each.  There are auto-arrange options available as well by calling the LayoutMDI() method on the MDIParent.
    Wednesday, June 22, 2005 5:16 PM
  • The code as posted doesn't work. I think you meant myForm as the parameter name?  In any event, here is what I think you are trying to do:



    Public Function CheckActiveMidChild2(ByVal myForm As Form) As Boolean

    Dim objMdiChild As Form

    Dim Bit As Boolean = False

    Try

    For Each objMdiChild In Me.MdiChildren

    If objMdiChild.Equals(myForm) Then

    Bit = True

    myForm.BringToFront()

    Exit For

    End If

    Next

    Catch ex As Exception

    End Try

    Return Bit

    End Function



     



    This does work for me.  Are you sure that your myForm variable is an open form, one that has not been closed?  For example, say you have captured an instance of an MDIChild form, MDIChild1, in a local variable on the parent.  If you then close MDIChild1, your local variable will still have a reference to it, but it is closed, so you can't bring it to front or show it again.  See this thread for more information.

    Tuesday, June 28, 2005 7:14 PM
  • Let MDIChild1 be the form always to be in the back, and MDIChild2 be the form to be on top.  Handle the Activated event for MDIChild1, and call Me.SendToBack().  This works if you click in the MDIChild1 client area, but not if you click in the window header non-client area.  You can, however, set MDIChild1.FormBorderStyle = FormBorderStyle.None, and MDIChild1.Dock = DockStyle.Fill. This will cause MDIChild1 to act as the background form for the MDIParent, which can be handy.  Typically, the MDIParent content area can contain only an image.

    Tuesday, June 28, 2005 10:47 PM
  • You're using VS2003 aren't you?, or at least not VS2005 Beta 2?  This behaviour has changed.  I remember a post about that somewhere, perhaps in this forum, but forums search appears to be broken right now...  I'll follow up should I learn more.

    I tried handling the MDIParent.MdiChildActivate. Enumerating through the MDIChildren, I looked at the type (or the instance, depending on how you did it) of the form, and if the child were not the special background form, then call BringToFront().  This worked only if there were 3 or more MDIChildren; it didn't work if there were 2.  In any event, here is that code:


    private void Form1_MdiChildActivate(object sender, System.EventArgs e)

    {

    if (this.ActiveMdiChild.GetType().Equals(typeof(MDIChild1)))

    {

    // ActiveMdiChild.SendToBack() did no good...

    //this.ActiveMdiChild.SendToBack();

    foreach (Form child in this.MdiChildren)

    {

    if (!child.GetType().Equals(typeof(MDIChild1)))

    {

    child.BringToFront();

    break;

    }

    }

    }

    }


     



    Saturday, July 2, 2005 12:24 AM

All replies

  • If you want to bring a particular child to the front, call its BringToFront() method.  If you want to arrange the children in a particular order, work through the children in reverse order and call BringToFront() on each.  There are auto-arrange options available as well by calling the LayoutMDI() method on the MDIParent.
    Wednesday, June 22, 2005 5:16 PM
  • Thers is one problem with that.
    It dosent seem to be working in  Beta 2

    mdiForm.BringToFront()

    Any one else having  this problem?

    Thanks
    Joe
    Tuesday, June 28, 2005 5:17 PM
  • Please provide repro steps that demonstrate BringToFront() failing.  It works for me.
    Tuesday, June 28, 2005 6:15 PM
  • Is there an easy way to keep one always in the back?
    Tuesday, June 28, 2005 6:19 PM

  • Public Function CheckActiveMidChild(ByVal my As Form) As Boolean

            Dim objMdiChild As Form = PMC_form.ActiveMdiChild
            Dim Bit As Boolean = False

            Try

                For Each objMdiChild In PMC_form.MdiChildren

                    If objMdiChild.Name.ToString.Equals(myForm.Name) Then
                        Bit = True
                        myForm.BringToFront()
                        Exit For
                    End If
                Next

            Catch ex As Exception

            End Try

            Return Bit

        End Function

    Tuesday, June 28, 2005 6:21 PM
  • The code as posted doesn't work. I think you meant myForm as the parameter name?  In any event, here is what I think you are trying to do:



    Public Function CheckActiveMidChild2(ByVal myForm As Form) As Boolean

    Dim objMdiChild As Form

    Dim Bit As Boolean = False

    Try

    For Each objMdiChild In Me.MdiChildren

    If objMdiChild.Equals(myForm) Then

    Bit = True

    myForm.BringToFront()

    Exit For

    End If

    Next

    Catch ex As Exception

    End Try

    Return Bit

    End Function



     



    This does work for me.  Are you sure that your myForm variable is an open form, one that has not been closed?  For example, say you have captured an instance of an MDIChild form, MDIChild1, in a local variable on the parent.  If you then close MDIChild1, your local variable will still have a reference to it, but it is closed, so you can't bring it to front or show it again.  See this thread for more information.

    Tuesday, June 28, 2005 7:14 PM
  • Thank you for the help that worked well!

    Basically what I’m doing is keeping them from opening multiple instances of the same form. So this works well I am able to reference the other form values or pass values to it with out having to create another instance of the form it’s already open. So I have created the function below in a class for what ever. 

    Edit: I just noticed i need to pass in the mdi parent as a var also to make this generic :)


    Public
    Function CheckActiveMidChild(ByVal myForm As Form) As Boolean

    Dim objMdiChild As Form

    Dim Bit As Boolean = False

    Try

    For Each objMdiChild In My.Forms.PMC_form.MdiChildren 'Mdi Parent

    If objMdiChild.Equals(myForm) Then

    Bit = True

    myForm.BringToFront()

    Exit For

    End If

    Next

    Catch ex As Exception

    End Try

    Return Bit

    End Function



     

    Tuesday, June 28, 2005 7:40 PM
  • The following function may be useful to you. It takes a Type as a parameter



    Private Function ActivateChild(ByVal formType As Type) As Form

    Dim form As Form

    Dim child As Form

    For Each form In Me.MdiChildren

    If form.GetType().Equals(formType) Then

    child = form

    End If

    Next

    If child Is Nothing Then

    child = System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(formType.FullName)

    child.MdiParent = Me

    child.Show()

    End If

    child.BringToFront()

    Return child

     

    End Function

    'This is an example of how to use it.  It is called from the Child3 menu item in the MDIParent Forms menu.  In this case nothing else is done with the return value, but you could for example set child.TopMost = true.

    Private Sub Child3ToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Child3ToolStripMenuItem.Click

    Dim child As MDIChild3

    child = ActivateChild(MDIChild3.GetType())

    End Sub


     

    Tuesday, June 28, 2005 9:54 PM
  • Let MDIChild1 be the form always to be in the back, and MDIChild2 be the form to be on top.  Handle the Activated event for MDIChild1, and call Me.SendToBack().  This works if you click in the MDIChild1 client area, but not if you click in the window header non-client area.  You can, however, set MDIChild1.FormBorderStyle = FormBorderStyle.None, and MDIChild1.Dock = DockStyle.Fill. This will cause MDIChild1 to act as the background form for the MDIParent, which can be handy.  Typically, the MDIParent content area can contain only an image.

    Tuesday, June 28, 2005 10:47 PM
  • What you said is pretty much exactly what I am attemping to do. I have,



    {
    //Constructor code...
    this.FormBorderStyle = FormBorderStyle.None;
    this.Dock = DockStyle.Fill;
    this.Activated += new EventHandler(Inner_Screen_Activated);
    //More Constructor code...
    }

    private void Inner_Screen_Activated(object sender, EventArgs e)
         {
            
    this.SendToBack();
         }

     


    but when "Inner_Screen" get the activated handler it does not get sent to back.

    Friday, July 1, 2005 10:29 PM
  • You're using VS2003 aren't you?, or at least not VS2005 Beta 2?  This behaviour has changed.  I remember a post about that somewhere, perhaps in this forum, but forums search appears to be broken right now...  I'll follow up should I learn more.

    I tried handling the MDIParent.MdiChildActivate. Enumerating through the MDIChildren, I looked at the type (or the instance, depending on how you did it) of the form, and if the child were not the special background form, then call BringToFront().  This worked only if there were 3 or more MDIChildren; it didn't work if there were 2.  In any event, here is that code:


    private void Form1_MdiChildActivate(object sender, System.EventArgs e)

    {

    if (this.ActiveMdiChild.GetType().Equals(typeof(MDIChild1)))

    {

    // ActiveMdiChild.SendToBack() did no good...

    //this.ActiveMdiChild.SendToBack();

    foreach (Form child in this.MdiChildren)

    {

    if (!child.GetType().Equals(typeof(MDIChild1)))

    {

    child.BringToFront();

    break;

    }

    }

    }

    }


     



    Saturday, July 2, 2005 12:24 AM
  • Ahh, yes I am using VS2003. :(
    Saturday, July 2, 2005 1:20 AM
  • I have 2 or 3 different MDI child windows.

    The user can Tile/Cascade/Maximize these but whenever I open or close a window, or return to Tiled mode from another state, I automatically re-order the windows to ensure that a specific one is at the top, and (if it exists) a specific one at the bottom.

     

    In VB6 I simply set the Z-Order of the ones I wanted to be at the top/bottom and this worked 100% of the time.

    When I converted to .Net I used SendToBack and BringToFront ... but it works only some of the time - depending which of these I call first different situations work. (In one case returning from Maximized to Tiled works , in the other Opening/Closing a window works - but nothing works in all cases.)

     

    If the user then MANUALLY clicks on my Tile toolbutton it almost always works - even though the exact same function is called. (Since the windows are already tiled all it does is move them into the correct order.

     

    I'm guessing that it is some kind of timming issue (The parent doesn't yet know about the 'new' window, or still thinks the one being closed exists, although that does not explain why moving from Maximized to Tiled would not work.)

     

    Anyone have any ideas?

    (I have tried throwing in Refresh, DoEvents, etc. before re-ordering but nothing works.)

     

     

    Tuesday, December 4, 2007 3:37 PM