Richie's profileThe Sandpit - "We hack s...BlogLists Tools Help

Blog


    May 13

    Adding Tab-key Support to the PropertyGrid Control

    The PropertyGrid control is convenient for adding object editing support with minimal code.  However, for some reason it does not support property navigation with the tab key.  Instead, clicking tab key will progressively set focus to other controls in your form.  This post provides a simple subclassed PropertyGrid with support for tab-key navigation of properties.

    image

    Below is the source code to a subclassed PropertyGrid control called TabbedPropertyGrid.  There were two major issues that needed to be overcome.  The first is that the PropertyGrid does not raise any keyboard events, to workaround this the subclassed PropertyGrid must hijack keyboard events from the parent form.  The second issue is that there is no intuitive way to navigate GridItems.  However, this MSDN forum thread provided a few clues to solve this using the Griditems and Parent property.

    public class TabbedPropertyGrid : PropertyGrid {
        public TabbedPropertyGrid() : base() { }
        public void SetParent(Form form) {
            // Catch null arguments
            if (form == null) {
                throw new ArgumentNullException("form");
            }
    
            // Set this property to intercept all events
            form.KeyPreview = true;
    
            // Listen for keydown event
            form.KeyDown += new KeyEventHandler(this.Form_KeyDown);
        }
        private void Form_KeyDown(object sender, KeyEventArgs e) {
            // Exit if cursor not in control
            if (!this.RectangleToScreen(this.ClientRectangle).Contains(Cursor.Position)) {
                return;
            }
    
            // Handle tab key
            if (e.KeyCode != Keys.Tab) { return; }
            e.Handled = true;
            e.SuppressKeyPress = true;
    
            // Get selected griditem
            GridItem gridItem = this.SelectedGridItem;
            if (gridItem == null) { return; }
    
            // Create a collection all visible child griditems in propertygrid
            GridItem root = gridItem;
            while (root.GridItemType != GridItemType.Root) {
                root = root.Parent;
            }
            List<GridItem> gridItems = new List<GridItem>();
            this.FindItems(root, gridItems);
    
            // Get position of selected griditem in collection
            int index = gridItems.IndexOf(gridItem);
    
            // Select next griditem in collection
            this.SelectedGridItem = gridItems[++index];
        }
        private void FindItems(GridItem item, List<GridItem> gridItems) {
            switch (item.GridItemType) {
                case GridItemType.Root:
                case GridItemType.Category:
                    foreach (GridItem i in item.GridItems) {
                        this.FindItems(i, gridItems);
                    }
                    break;
                case GridItemType.Property:
                    gridItems.Add(item);
                    if (item.Expanded) {
                        foreach (GridItem i in item.GridItems) {
                            this.FindItems(i, gridItems);
                        }
                    }
                    break;
                case GridItemType.ArrayValue:
                    break;
            }
        }
    }

    After adding the TabbedPropertyGrid to your form, the form must be parsed into the control using the SetParent method.

    public partial class Form1 : Form {
        public Form1() {
            InitializeComponent();
    
            // Assign the form to the propertygrid
            this.tabbedPropertyGrid1.SetParent(this);
            this.tabbedPropertyGrid1.SelectedObject = this;
        }
    }

    Known Issues:  Shift-Tab does not select properties in reverse order.

    Technorati Tags: ,,