Handling Tab key in Inventor .Net Forms

By Philippe Leefsma

When displaying a custom .Net form, typically during a command to gather inputs or allow the user to control your command’s behavior, you may have noticed than your form will not honor the tab indices you may have defined when designing the form under Visual Studio editor. Actually pressing the Tab key will have no effect.

The reason is that Inventor is setting some low level hook mechanism to intercept keypress events such as Tab or Enter, so you won’t be able to directly redirect those events to your controls unless you use some low level and probably complex workarounds.

The code proposed below illustrates a way to handle and respond to Tab keypress events with some custom logic. It basically consist in instantiating the AdnTabIndexManager class and let it initialize an internal dictionary with the controls tab indices you defined at design time using Contro.TabIndex property.

 

/////////////////////////////////////////////////////////////////

// Use: Handle form controls focus when user presses Tab key

// Author: Philippe Leefsma, 2012

/////////////////////////////////////////////////////////////////

public class AdnTabIndexManager

{

    private Form _form;

 

    private SortedDictionary<int, Control> _ctrlDic;

 

    private SortedDictionary<int, Control>.Enumerator _ctrlDicEnum;

 

    // Constructor, simply pass in the form

    // the TabIndexManager will take care of

    // initializing the form controls tab indices

    public AdnTabIndexManager(Form form)

    {

        _form = form;

 

        // Required in order to be able to catch form events

        _form.KeyPreview = true;

 

        _ctrlDic = new SortedDictionary<int, Control>();

 

        if (LoadControlsTabIndices(form.Controls))

        {

            _form.KeyPress += new KeyPressEventHandler(OnKeyPress);

 

            _ctrlDicEnum = _ctrlDic.GetEnumerator();

        }

    }

 

    // Loads tab indices recursively if form contains

    // container controls

    private bool LoadControlsTabIndices(

        System.Windows.Forms.Control.ControlCollection ctrls)

    {

        try

        {

            foreach (Control ctrl in ctrls)

            {

                // We don’t set focus to containers,

                // groupboxes or panels because

                // it is usually useless

                if (!(ctrl is ContainerControl) &&

                    !(ctrl is GroupBox) &&

                    !(ctrl is Panel))

                {

                    int index = ctrl.TabIndex;

 

                    //prevents duplicates tabIndex

                    //can hap
pen in case of nested controls

                    while (_ctrlDic.ContainsKey(index))

                        ++index;

 

                    _ctrlDic.Add(index, ctrl);

                }

 

                LoadControlsTabIndices(ctrl.Controls);

            }

 

            return true;

        }

        catch

        {

            return false;

        }

    }

 

    // Finds the nested control with focus

    // In case of container controls

    // we need to iterate to find the control

    // that really has focus, such as a TextBox

    // inside a GroupBox

    private Control GetActiveControl()

    {

        if (_form.ActiveControl != null)

        {

            Control trueActiveCtrl = _form.ActiveControl;

 

            while (trueActiveCtrl is ContainerControl)

            {

                ContainerControl cctrl = trueActiveCtrl as

                    ContainerControl;

 

                trueActiveCtrl = cctrl.ActiveControl;

            }

 

            return trueActiveCtrl;

        }

 

        return null;

    }

 

    // Initializes the control enumerator to the

    // activeControl

    private void InitializeCtrlEnum(Control activeCtrl)

    {

        if (activeCtrl != null)

        {

            _ctrlDicEnum = _ctrlDic.GetEnumerator();

            _ctrlDicEnum.MoveNext();

 

            while (_ctrlDicEnum.Current.Value != null)

            {

                if (_ctrlDicEnum.Current.Value == activeCtrl)

                    return;

 

                _ctrlDicEnum.MoveNext();

       &
#160;   
}

        }

    }

 

    // Returns the next control based on TabIndices

    // initialized in the member dictionary

    private Control NextControl

    {

        get

        {

            Control trueActiveCtrl = GetActiveControl();

 

            if (_ctrlDicEnum.Current.Value != trueActiveCtrl)

                InitializeCtrlEnum(trueActiveCtrl);

 

            _ctrlDicEnum.MoveNext();

 

            if (_ctrlDicEnum.Current.Value == null)

            {

                _ctrlDicEnum = _ctrlDic.GetEnumerator();

                _ctrlDicEnum.MoveNext();

            }

 

            return _ctrlDicEnum.Current.Value;

        }

    }

 

    // Tab key pressed event handler

    private void OnKeyPress(

        System.Object sender,

        System.Windows.Forms.KeyPressEventArgs e)

    {

        if (e.KeyChar == ‘\t’)

        {

            //gives focus to next control

            this.NextControl.Focus();

        }

    }

}

 

Here is an example that illustrates how to use the AdnTabIndexManager:

 

/////////////////////////////////////////////////////////////

// Use: a small utility class t
o create child dialogs

//

/////////////////////////////////////////////////////////////

class WindowWrapper : System.Windows.Forms.IWin32Window

{

    private IntPtr mHwnd;

 

    public WindowWrapper(IntPtr handle)

    {

        mHwnd = handle;

    }

 

    public IntPtr Handle

    {

        get

        {

            return mHwnd;

        }

    }

}

 

public partial class CommandForm : Form

{

    AdnTabIndexManager _TabIndexManager;

 

    public CommandForm()

    {

        InitializeComponent();

 

        _TabIndexManager = new AdnTabIndexManager(this);

    }

 

    // Use as follow:

    // f.Show((IntPtr)Inventor.Application.MainFrameHWND);

    public void Show(IntPtr hwndParent)

    {

        this.Show(new WindowWrapper(hwndParent));

    }

 

    // rest of form class implementation…

 

 

<

p style=”line-height: normal;margin: 0in 0in 0pt” class=”MsoNormal”> 


Comments

Leave a Reply

Discover more from Autodesk Developer Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading