dexLabelProvider & LinkField explained

image

The dexLabelProvider is a component that implements IExtenderProvider, thus adding an extra property (LinkField) to label components dropped onto a DexUI form or forms that inherit from it. The provider is used by the DexUI form’s onPaint to draw a line between label (or linklabel) and control defined in the LinkField property.

In more detail

Add a DexUI form to your add-in project or inherit form a dexUI form and in the tray is found a dexLabelProvider.

image

The dexLabelProvider keeps track of the labels on the form that are linked visually to text boxes, and thus should have a line connecting them on the User Interface in order to match into the “visual feel” of GP. In the screenshot below you can see the label and text box, both selected in Visual Studio, see a line joins them, a line drawn by the form paint. That it should be drawn is held by the label provider as a hash table of controls to link in this way.

image

The dexLabelProvider implements the IExtenderProvider that allows components to add their own properties to other components in the Visual Studio UI designer. In the case of dexLabelProvider, it adds the following decoration to the DexLabelProvider, so as to impose a LinkField property to other components on the form.

[ProvideProperty("LinkField", typeof(Label))]

However the other method to implement the IExtenderProvider is the CanExtend method. In the case of dexLabelProvider it is set to return true only if the object is Label, hence it will only add the property to controls of type label.

image

The class is very simple, holding a HashTable of controls it is extending (i.e. controls it is adding visual link lines to).

DexUIForm creates an instance of dexLabelProvider to keep track of the extended labels.

In passing it is worth mentioning that DexUIForm checks to see if that component is a LinkLabel or Label type, if so it sets that control’s AutoSize to false, this is why whenever you set AutoSize to true, it reverts to false.

The OnPaint of DexUIForm does the business of drawing the line. Each control is checked to see if it is a label or linklabel type, if it is, then it asks the label provider to supply the control that links to this label (if any). It does this by looking up in the hash label the name of the linked control, using the current controls name as key. It then returns that control from the form control collection (usually a text box or similar). “promptLink” represents the linked control in the code snip below.

In the snippets below we can see that depending on the relative position of link label and control it links to, two points are derived, between which a line is drawn, the link we see in the UI linking the two controls.

if (promptLink != null && e.ClipRectangle.IntersectsWith(this.GetControlRectangle(control as Label, promptLink)))
                      {  
                            Point empty = Point.Empty;
                            Point empty2 = Point.Empty;
                            if (control.Bounds.Left < promptLink.Bounds.Left)
                            {
                                empty2 = new Point(control.Bounds.Left - 3, control.Bounds.Bottom + 2);
                                empty = new Point(promptLink.Bounds.Left, control.Bounds.Bottom + 2);
                            }
                            else if (control.Bounds.Right > promptLink.Bounds.Right + 3)
                            {
                                empty2 = new Point(control.Bounds.Right + 3, control.Bounds.Bottom + 2);
                                empty = new Point(promptLink.Bounds.Right, control.Bounds.Bottom + 2);
                            }
                            if (empty2 != Point.Empty)
                            {
                                e.Graphics.DrawLine(new Pen(ColorHelper.Instance.GetFieldBorderColor()), empty2, empty);
                            }
                        }
private Rectangle GetControlRectangle(Label control, Control link)
{
    if (control.Bounds.Left < link.Bounds.Left - 3)
    {
        return new Rectangle(control.Bounds.Left - 3, control.Bounds.Bottom + 2, link.Bounds.Left - control.Bounds.Left + 3, 1);
    }
    if (control.Bounds.Right > link.Bounds.Right + 3)
    {
        return new Rectangle(control.Bounds.X - 3, control.Bounds.Bottom + 2, control.Bounds.Right - link.Bounds.Right + 3, 1);
    }
    return new Rectangle(0, 0, 0, 0);
}

If the label is to left of the control, the line is from the point at the bottom left corner of the label to the bottom left of the control it links to. If the label is to the right of the control, the line goes from the right hand bottom corner to the right hand bottom corner of the linked control. Notice too, that no account of the vertical position is taken, it is up to the developer to position the controls such that the line intersects correctly in a vertical axis.

A simple implementation that gives Dynamics GP Visual Studio Tools developers the ability to have native feeling forms.