Solved

MDI: Change CTRL-Tab behaviour

Posted on 2008-10-21
6
1,560 Views
Last Modified: 2013-12-17
Hi experts

How can I change the ctrl-tab behaviour of a MDI-Container.
Normally it just "loops" through all the mdi-children, but need to exclude some of them.
Where and how can I change this behaviour?

I'm using .NET 2.0, VS2008, c# and WinForms
0
Comment
Question by:Arikael
  • 3
  • 3
6 Comments
 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 22768537
Hi Arikael,

In your MdiParent Form, the gray area where the MdiChild forms appear is known as the MdiClient window.  Whenever you press Ctrl-Tab, this window will get a WM_MDINEXT message which causes it to select the next MdiChild.

See WM_MDINEXT:
http://msdn.microsoft.com/en-us/library/ms644918(VS.85).aspx

In my example below, whenever an MdiChild of Type Form2 is selected as a result of a Ctrl-Tab, I send another WM_MDINEXT message causing the next MdiChild to be selected.  This technically doesn't SKIP Form2 since it is actually selected for a split second before the next MdiChild gets selected.

Sorry that it is in VB.Net...I'm still coming to grips with coding in C#.  =\

Hopefully you can make sense of what is going on...
Public Class Form4
 

    Private client As MyMdiClient
 

    Private Sub Form4_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        For Each ctl As Control In Me.Controls

            If TypeOf ctl Is MdiClient Then

                client = New MyMdiClient(ctl, Me)

                Exit For

            End If

        Next
 

        Dim f1 As New Form1

        f1.MdiParent = Me

        f1.Show()
 

        Dim f2 As New Form2

        f2.MdiParent = Me

        f2.Show()
 

        Dim f3 As New Form3

        f3.MdiParent = Me

        f3.Show()

    End Sub
 

    Private Class MyMdiClient

        Inherits NativeWindow
 

        Private MyMdiParent As Form

        Private Const WM_MDINEXT As Integer = &H224
 

        Private Declare Function SendMessage Lib "user32" Alias "SendMessageW" _

            (ByVal handle As IntPtr, ByVal wMsg As Integer, _

            ByVal wParam As Integer, ByVal lParam As Integer) As Integer
 

        Public Sub New(ByVal client As MdiClient, ByVal parent As Form)

            Me.AssignHandle(client.Handle)

            Me.MyMdiParent = parent

        End Sub
 

        Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)

            Select Case m.Msg

                Case WM_MDINEXT

                    Debug.Print("WM_MDINEXT")

                    Debug.Print("Before: " & Me.MyMdiParent.ActiveMdiChild.Name)
 

                    MyBase.WndProc(m)

                    Application.DoEvents()
 

                    Debug.Print("After: " & Me.MyMdiParent.ActiveMdiChild.Name)
 

                    ' Skip over to the next MdiChild if the current one is of Type Form2

                    If TypeOf Me.MyMdiParent.ActiveMdiChild Is Form2 Then
 

                        ' *** BE CAREFUL! ***
 

                        ' If all the MdiChildren are of Type Form2 then this

                        ' will cause an infinite loop...
 

                        SendMessage(Me.Handle, WM_MDINEXT, 0, 0)

                    End If

                    Exit Sub
 

            End Select

            MyBase.WndProc(m)

        End Sub
 

    End Class
 
 

End Class

Open in new window

0
 
LVL 3

Author Comment

by:Arikael
ID: 22773677
thanks, I will have a look at it today
0
 
LVL 3

Author Comment

by:Arikael
ID: 22774580
here is the code I used (c#)
0x0224 is 548 in the decimal system.
And I put the code into the MdiParent, into my class from which every MdiChild inherits but the code within

if(m.Msg == WM_MDINEXT)

never gets executed, because the m.Msg is never 548.
Any ideas why this could happen?
private const int WM_MDINEXT = 0x0224;
 

protected override void WndProc(ref Message m)

        {

            System.Diagnostics.Debug.WriteLine(m.Msg);

            if(m.Msg == WM_MDINEXT)

            {

                base.WndProc(ref m);
 

                if(this.ActiveMdiChild is MetaDetail)

                {

                    Application.DoEvents();

                    PostMessage(this.Handle, WM_MDINEXT, 0, 0);

                }

            }
 

            base.WndProc(ref m);

        }
 

        [DllImport("user32.dll")]

        public static extern System.IntPtr PostMessage(System.IntPtr hwnd, int msg, int wParam, int lParam);

Open in new window

0
Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

 
LVL 85

Accepted Solution

by:
Mike Tomlinson earned 500 total points
ID: 22776541
As I said before, the WM_MDINEXT message gets sent to the MdiClient window (the gray area in the MdiParent).  This is a child window of the main MdiParent.  If you look in the Load() event, I am iterating over the Controls() collection looking for this control:

    Private Sub Form4_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        For Each ctl As Control In Me.Controls
            If TypeOf ctl Is MdiClient Then
                client = New MyMdiClient(ctl, Me)
                Exit For
            End If
        Next
    End Sub

I pass the MdiClient to an instance of the MyMdiClient() class...which Inherits from NativeWindow().  So in my example, WndProc() is actually for the MdiClient ONLY and not the entire MdiParent.

I'll code up a working example in C# 2005 Express today if you can't figure it out.
0
 
LVL 85

Assisted Solution

by:Mike Tomlinson
Mike Tomlinson earned 500 total points
ID: 22777990
Here is a working C# version:  (C# 2005 Express)
using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

using System.Diagnostics;

using System.Runtime.InteropServices;
 

namespace WindowsApplication1

{

    public partial class frmMdiParent : Form

    {

        public frmMdiParent()

        {

            InitializeComponent();

        }
 

        private MyMdiClient client = null;
 

        private void frmMdiParent_Load(object sender, EventArgs e)

        {

            foreach (Control ctl in this.Controls)

            {

                if (ctl is MdiClient)

                {

                    this.client = new MyMdiClient((MdiClient)ctl, this);

                }

            }
 

            Form1 f1 = new Form1();

            f1.MdiParent = this;

            f1.Show();
 

            Form2 f2 = new Form2();

            f2.MdiParent = this;

            f2.Show();
 

            Form3 f3 = new Form3();

            f3.MdiParent = this;

            f3.Show();

        }
 

        private class MyMdiClient : NativeWindow

        {
 

            private Form MyMdiParent = null;

            private const int WM_MDINEXT = 0x224;
 

            [DllImport("user32.dll")]

            public static extern int PostMessage(IntPtr handle, int msg, int wParam, int lParam);

            

            public MyMdiClient(MdiClient mdiClient, Form mdiParent)

            {

                this.AssignHandle(mdiClient.Handle);

                this.MyMdiParent = mdiParent;

            }
 

            protected override void WndProc(ref Message m)

            {

                switch (m.Msg)

                {

                    case WM_MDINEXT:

                        Debug.Print("WM_MDINEXT");

                        Debug.Print("Before: " + this.MyMdiParent.ActiveMdiChild.Name);
 

                        base.WndProc(ref m);

                        Application.DoEvents();
 

                        Debug.Print("After: " + this.MyMdiParent.ActiveMdiChild.Name);
 

                        // Skip over Form2 when Ctrl-Tab is pressed

                        if (this.MyMdiParent.ActiveMdiChild is Form2)

                        {                            

                            PostMessage(this.Handle, WM_MDINEXT, 0, 0);

                        }
 

                        return;
 

                }
 

                base.WndProc(ref m);

            }
 

        }
 

    }

}

Open in new window

0
 
LVL 3

Author Comment

by:Arikael
ID: 22783564
ah, sorry, I didn't unterstand the term MdiClient at first.
Now everything works as expected

I changed the code in MdiParent to (see code below), client was not defined in the c# code.

P.S. I raised the points to 500, thank you very much for your help :-)
  MyMdiClient client;
 

            foreach(Control ctl in this.Controls)

            {

                if(ctl is MdiClient)

                {

                    client = new MyMdiClient((MdiClient)ctl, this);

                    break;

                }

            }

Open in new window

0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Suggested Solutions

Welcome my friends to the second instalment and follow-up to our Minify and Concatenate Your Scripts and Stylesheets (http://www.experts-exchange.com/Programming/Languages/.NET/ASP.NET/A_4334-Minify-and-Concatenate-Your-Scripts-and-Stylesheets.html)…
It was really hard time for me to get the understanding of Delegates in C#. I went through many websites and articles but I found them very clumsy. After going through those sites, I noted down the points in a easy way so here I am sharing that unde…
Internet Business Fax to Email Made Easy - With eFax Corporate (http://www.enterprise.efax.com), you'll receive a dedicated online fax number, which is used the same way as a typical analog fax number. You'll receive secure faxes in your email, fr…
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…

707 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

14 Experts available now in Live!

Get 1:1 Help Now