How to: Create custom 'fixed' item

  • 7 minutes to read

Specific layout items are constantly displayed in the Customization Form, and are never removed from the Customization Form when dragged onto a Layout Control. These items are called 'fixed'. They come first, and are painted bold in the Customization Form. Currently, the Layout Control supports the following predefined 'fixed' items: Empty Space Items, Label, Separator and Splitter.

The LayoutControl.RegisterFixedItemType method allows a custom 'fixed' item to be registered for runtime use in a Layout Control. This item will be constantly displayed in the Customization Control at runtime, and when an end-user drops it onto a Layout Control, your custom code will be called and an instance of it will be created.

First, create a custom 'fixed' item by deriving it from the LayoutControlItem class and implementing the DevExpress.XtraLayout.IFixedLayoutControlItem interface. Second, the item must be registered via the LayoutControl.RegisterFixedItemType method.

The following example shows how to create a custom 'fixed' item, named MyFixedLabelItem, representing a link displaying a URL. The item will contain a LinkLabel control. The following methods have been overridden and added:

  • The TypeName property must return the name of the "fixed" item's type. This property must always be overridden when creating custom layout items.
  • The MyFixedLabelItem constructor contains initialization code. This constructor is called when a layout item is registered within the Layout Control, the "fixed" item is dropped onto the control or when a layout is restored from a data store.
  • The Text property specifies the current link's text. This property is overridden to support layout serialization. This property's value is saved/restored when a layout is saved to/restored from a data store.
  • The new Link property specifies the current link's text. It's synchronized with the layout item's Text property. This property will be displayed in the Property Grid in the Customization Form. See below.

    When the Link property is changed, the new link is automatically assigned to the Text property of the embedded LinkLabel control (see the OnLinkChanged method).

  • The IFixedLayoutControlItem.OnCreateControl method. This method is called when an instance of the "fixed" layout item is about to be created (when the "fixed" item is dragged and dropped from the Customization Form onto the form or a layout is restored from a data store). Typically, this method must be overridden to create a control to be displayed in the layout item.
  • The IFixedLayoutControlItem.OnInitialize method. Typically, this method must be overridden to initialize the created item. This method is called after the OnCreateControl method.
  • The IFixedLayoutControlItem.OnDestroy method. In this method, destroy the control that has been previously created and release all allocated resources.
  • The IFixedLayoutControlItem.CustomizationName property must return the text representing the "fixed" item in the Customization Form.
  • The IFixedLayoutControlItem.CustomizationImage property must specify an image that will be displayed next to the text specified by the CustomizationName property.
  • The IFixedLayoutControlItem.AllowChangeTextLocation property must return a value that specifies whether a specific menu item is available via the Context Menu, that allows an end-user to change the item's text location.
  • The IFixedLayoutControlItem.AllowChangeTextVisibility property must return a value that specifies whether a specific menu item is available via the Context Menu, allowing an end-user to hide/show the item's text.
  • The IFixedLayoutControlItem.AllowClipText property must return a value that specifies whether the item's caption can be clipped, or it's always displayed in its entirety.

Properties of layout items are displayed in the Customization Form's Property Grid. The Layout Control allows only specific properties to be displayed for specific types of layout items. To do this, a BasePropertyGridObjectWrapper descendant must be created. Public properties that this class introduces will be displayed in the Property Grid. Other properties will not be available.

A custom BasePropertyGridObjectWrapper descendant must be associated with a specific layout item's type via the LayoutControl.RegisterCustomPropertyGridWrapper method. As a result, when selecting a layout item of this type, a corresponding BasePropertyGridObjectWrapper object will be used, that will specify which properties to display.

In the example, the MyFixedLabelPropertiesWrapper class is created and associated with the MyFixedLabelItem class. The MyFixedLabelPropertiesWrapper class contains only one public property - Link. When any layout item of the MyFixedLabelItem type is selected, the Property Grid will display only the Link property.

The following image shows the result:

CustomFixedItem

        layoutControl1.RegisterCustomPropertyGridWrapper(typeof(MyFixedLabelItem),
            typeof(MyFixedLabelPropertiesWrapper));
        layoutControl1.RegisterFixedItemType(typeof(MyFixedLabelItem));
// The custom 'fixed' item.
public class MyFixedLabelItem : LayoutControlItem, IFixedLayoutControlItem {
    // Must return the name of the item's type
    public override string TypeName { get { return "MyFixedLabelItem"; } }
    string linkCore;
    Control controlCore = null;

    public string Link {
        get { return linkCore; }
        set {
            if (Link == value) return;
            this.linkCore = value;
            OnLinkChanged();
        }
    }
    void label_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) {
        //...
    }
    public override string Text {
        get { return Link; }
        set { Link = value; }
    }
    // This method is called when the Link property is changed.
    // It assigns the new link to the embedded LinkLabel control.
    protected void OnLinkChanged() {
        controlCore.Text = Link;
    }

    // Initialize the item.
    void IFixedLayoutControlItem.OnInitialize() {
        this.linkCore = "www.devexpress.com";
        OnLinkChanged();
        TextVisible = false;
    }
    // Create and return the item's control.
    Control IFixedLayoutControlItem.OnCreateControl() {
        this.controlCore = new LinkLabel();
        ((LinkLabel)controlCore).LinkClicked += label_LinkClicked;
        return controlCore;
    }
    // Destroy the item's control.
    void IFixedLayoutControlItem.OnDestroy() {
        if (controlCore != null) {
            ((LinkLabel)controlCore).LinkClicked -= label_LinkClicked;
            controlCore.Dispose();
            controlCore = null;
        }
    }
    string IFixedLayoutControlItem.CustomizationName { get { return "DevExpress Link"; } }
    Image IFixedLayoutControlItem.CustomizationImage { get { return null; } }
    bool IFixedLayoutControlItem.AllowChangeTextLocation { get { return false; } }
    bool IFixedLayoutControlItem.AllowChangeTextVisibility { get { return false; } }
    bool IFixedLayoutControlItem.AllowClipText { get { return false; } }
    ILayoutControl IFixedLayoutControlItem.Owner { get { return base.Owner; } set { base.Owner = value; } }
}

// Specifies which properties to display in the Property Grid
public class MyFixedLabelPropertiesWrapper : BasePropertyGridObjectWrapper {
    protected MyFixedLabelItem Label { get { return WrappedObject as MyFixedLabelItem; } }
    [Description("The link's text")]
    public string Link { get { return Label.Link; } set { Label.Link = value; } }
    public override BasePropertyGridObjectWrapper Clone() {
        return new MyFixedLabelPropertiesWrapper();
    }
}