XtraLayoutControl in action : Customizable PropertyGrid in 15 min

WinForms Team Blog
07 April 2006

The PropertyGrid control is often used to view control properties. This article demonstrates how to customize the XtraLayoutControl to create a simple PropertyGrid component.
This example doesn't provide a full-functional replacement to the standard PropertyGrid component. The aim of this article is to show how to create dynamic layouts in a very short time. The XtraLayoutControl is very powerful in creating layouts on the fly. You can add, remove, hide, move and customize items at any moment.
Assume that we have a form with an empty LayoutControl docked to the form's right edge like in the picture below.

 

In this example, we will demonstrate how to display all the public properties of the selected control in the XtraLayoutControl. A user will be able to select a control and its properties will be listed as a set of labeled text boxes arranged one under another.
Selecting a target control will be similar to the Microsoft Spy's functionality, i.e a user will be able to press the left mouse button on the LayoutControl and then move the mouse pointer to the target control. When the mouse button is released over a specific control, its properties will be listed in the LayoutContorol. The following code implements this behavior.

private void layoutControl1_MouseDown(object sender, MouseEventArgs e) {
            layoutControl1.Capture = true;
            Cursor.Current = Cursors.Hand;
        }
private void layoutControl1_MouseUp(object sender, MouseEventArgs e) {
            Cursor.Current = Cursors.WaitCursor;
            layoutControl1.Capture = false;
            Point p = new Point(e.X, e.Y);
            p = layoutControl1.PointToScreen(p);
            p = this.PointToClient(p);
            foreach(Control control in Controls) {
                if(control.Bounds.Contains(p) && control != layoutControl1) {
                    ShowObjectProoperties(control);
                }
            }
            Cursor.Current = Cursors.Default;
   }
The selected object's properties are displayed in the LayoutControl in the ShowObjectProperties method:

private void ShowObjectProperties(object target) {
            Type type = target.GetType();
            PropertyInfo[] propertyInfoArray = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
            layoutControl1.BeginInit();
            layoutControl1.Root.Items.Clear();
            int count = layoutControl1.Controls.Count;
            for(int i = 3; i < count; i++) {
                layoutControl1.Controls[3].Parent = null;
            }
            layoutControl1.OptionsItemText.TextOptions.HAlignment = DevExpress.Utils.HorzAlignment.Far;
            foreach(PropertyInfo property in propertyInfoArray) {
                    TextBox textBox = new TextBox();
                    textBox.Name = "textbox_" + property.Name;
                    object obj = property.GetValue(target, null);   
                    textBox.Text = obj == null ? "null" :obj.ToString();
                    BaseLayoutItem item = layoutControl1.AddItem(property.Name, textBox);
                    item.Name = "item_" + property.Name;
                    item.Padding.All = 1;
            }
            layoutControl1.EndInit();
        }

Let's look into it.
First, we need to clear the previous layout in the LayoutControl:

            layoutControl1.Root.Items.Clear();
            int count = layoutControl1.Controls.Count;
            for(int i = 3; i < count; i++) {
                layoutControl1.Controls[3].Parent = null;
            }

Secondly, we want to align the text of the layout items to the right edge, so we customize the layoutControl1.OptionsItemText.TextOptions property which specifies the default text settings for all layout items:

layoutControl1.OptionsItemText.TextOptions.HAlignment = DevExpress.Utils.HorzAlignment.Far;
 

Next, the names of the control's properties and their values are obtained using reflection. And for each property a layout item is created, which contains a TextBox control. The item's label displays the property's name:

foreach(PropertyInfo property in propertyInfoArray) {
                    TextBox textBox = new TextBox();
                    textBox.Name = "textbox_" + property.Name;
                    object obj = property.GetValue(target, null);   
                    textBox.Text = obj == null ? "null" :obj.ToString();
                    BaseLayoutItem item = layoutControl1.AddItem(property.Name, textBox);
                    item.Name = "item_" + property.Name;
                    item.Padding.All = 1;
            }

Please make sure that original names are assigned to the created layout items and text boxes. This is necessary for the serialization mechanism to work properly and this also affects the availability of the undo and redo operations and storing/restoring the LayoutControl's layout to an external data store (for instance, XML).
Note that the code that creates the layout is wrapped in the BeginInit and EndInit methods. These methods allow you to avoid flickering while changing the layout, as the XtraLayoutControl is not updated after the BeginInit method has been called until the EndInit method is called.
Now you can run the application. If you select the button1 control the result will be as in the image below: 
 

Only 25 lines of code was writen to create a layout. With a minimum of efforts we emulate the PropertyGrid, but our solution provides the following benefits compared to the standard control as they are natively supported by the XtraLayoutControl:
-         Fully customizeable layout
-         Support for the DevExpress skinning and LookAndFeel technologies
-         Customizable layout items
-         Consistent tab order
-         Support for shortcuts (you can just add '&' to LayoutItem.Text to add a shortcut)

no comments
No Comments

Please login or register to post comments.