# Displaying a value

The value part of a Property can be drawn in two ways:

  • Generically by the PropertyValue class drawing engine.
  • By an optional PropertyLook class attached to the Property.

# Generic display

In generic display, the drawing engine:

  1. Determines if the Property has an attached UITypeEditor.
  2. Determines if the value has an attached ImageList.
  3. Uses a string to represent the value.

For a detailed explanation of each step, see below.

# Attached UITypeEditor

The drawing engine first determines if the Property has an attached UITypeEditor.


  • MSPG uses the UITypeEditor class, part of the .Net framework (see Editing a value) to provide an editing mechanism for a given data type.
  • Some editors draw a small representation of the value at the left of the string, e.g. the ColorEditor. That’s why the SPG code checks to see if such an editor is available for the drawing and assigns it, unless told otherwise.

# Attached ImageList

The drawing engine next determines if the value has an attached ImageList, and if a current image index has been set.

# > To set the current image index

PropertyValue value = propEnum.Property.Value;
value.ImageList = ...;
value.CurrentImageListIndex = ...;

# > To control the size of the displayed image

value.ImageSize = new Size(16, 16);

If you don’t specify a size, the engine uses the Property height.

# A string to represent the value

Finally, the drawing engine uses a string to represent the value. This string is returned by the TypeConverter class attached to the property or property type.

If you specify your own TypeConverter classes, be aware that SPG supplies a context instance in its various Convert methods. This is a PropertyTypeDescriptorContext class, that:

  • Correctly sets the Instance and the PropertyDescriptor properties.
  • Supplies a reference to a PropertyEnumerator object that points to the Property.

Generally speaking, each time an ITypeDescriptorContext class is expected, SPG supplies its own PropertyTypeDescriptorContext.

The CultureInfo parameter, which is customizable per Property, is also passed to various TypeConverter methods.

# Optional PropertyLook class

The PropertyLook class - and any custom class derived from it - displays values in ways not handled by the generic engine.


SPG comes with a number of built-in looks.

In most cases, when you assign a look to a Property, you must also assign the corresponding editing mechanism. For example, if you display an enumeration as radio buttons, the user does not expect to be presented with a generic listbox for editing!

# Assigning a look

It is possible to assign a look with an attribute. This is useful for Properties created in Full Reflection Mode.


This example makes full use of the PropertyLook attribute:

[PropertyLook("Color", typeof(PropertyAlphaColorLook))]
public Pen OutlinePen {
  • The first line instructs SPG that the OutlinePen property will be depicted with a PropertyPenLook class.
  • The second line assigns a specific look class to the Color Property – a very powerful way to customize sub properties whose code is inaccessible.

# > Setting a look at runtime

It is also possible to set a look at runtime:

propEnum.Property.Value.Look = new PropertyProgressBarLook(true, "{0}%");

# > Configuring a look at runtime

Setup a look at runtime by casting it to the proper class. For the previous example, the code would be:

(propEnum.Property.Value.Look as PropertyProgressBarLook).Format = "{0}px";

# SPG built-in Look classes

PropertyAlphaColorLook PropertyCheckboxLook PropertyColorLook
PropertyDateTimeLook PropertyFontNameLook PropertyMaskedEditLook
PropertyMultilineEditLook PropertyPasswordLook PropertyPenLook
PropertyProgressBarLook PropertyRadioButtonLook PropertyUnitLook

# > PropertyAlphaColorLook

Draws a classic checkerboard behind the chosen transparent color.

# > PropertyCheckboxLook

Draws one or more checkboxes.

It must be associated with boolean (which can be nullable) or any type publishing only 2 possible values, enumeration or with ICollection data types.

# > PropertyColorLook

Draws a simple color box with the color data just inside.

This is identical in function to the ColorEditor in the .Net framework, but offers improved drawing of the content. The color name/value can be removed (and the color box will take all the space) by passing true to the PropertyColorLook constructor.

# > PropertyDateTimeLook

Displays a date/time string with the correct format (time, short date, long date), in the same manner as the true .Net DateTimePicker control.

The class has two properties which act like their DateTimePicker counterparts:

  • Format
  • CustomFormat

Set them on the look so that the inplace control knows how to configure itself:

propEnum = AppendProperty(upDownCategory, _id++, "Time", this, "Time", "");
propEnum.Property.Feel = GetRegisteredFeel(PropertyGrid.FeelDateTime);
propEnum.Property.Look = new PropertyDateTimeLook("HH:mm");

# PropertyFontNameLook

Shows the name of a font with a small sample at the left side.

This is identical in function to the FontNameEditor in the .Net framework, but offers improved drawing of the content.

# > PropertyFullWidthButtonLook

Draws a button on the full width of the Property value column.

It must be used with the button and UITypeEditor feels when no textbox is displayed and when they are configured to also show a full width button.

# > PropertyMaskedEditLook

Draws a value exactly as drawn by a MaskedTextBox.

You can pass the Mask and the Promp*tChar in the constructor, or later, using properties with the same names.

# > PropertyMultilineEditLook

Forces a multiline inplace control to display text as rendered in a multiline textbox.


Here, the HeightMultiplier property sets the row height as a multiple of the single line height:

propEnum = AppendProperty(parentEnum, id, "Multiline", this, "MyString", "");
propEnum.Property.Value.Feel = GetRegisteredFeel(PropertyGrid.FeelMultilineEdit);
propEnum.Property.HeightMultiplier = 3;
propEnum.Property.Value.Look = new PropertyMultilineEditLook();

# > PropertyPasswordLook

Displays a value as bullets.

You can apply this look explicitly, or set the Property's PasswordPropertyText attribute so that this look will be selected along with the correct inplace control.

# > PropertyPenLook

Displays a line as if drawn by the Property’s underlying pen.

This provides an intuitive way of selecting a pen. A Property with this look cannot have an inplace control (i.e. no feel), since it makes no sense for the user to enter a string.

PropertyPenLook is the typical example of a look that exploits all the drawing area to represent the underlying data.

# > PropertyProgressBarLook

Shows a progress bar plus optional non-editable value for an integer property.

A Property with this look cannot have an inplace control, since it makes no sense for the user to enter a string.

The value can be formatted:

propEnum = AppendManagedProperty(parentEnum, id, "Progress", typeof(int), 0, "");
propEnum.Property.Look = new PropertyProgressBarLook(true /* drawFrame*/, "{0}%");

Set the progress bar bounds by applying a PropertyValidatorMinMax validator:

propEnum.Property.Value.Validator = new PropertyValidatorMinMax(0, 100);

# > PropertyRadioButtonLook

Draws multiple radiobuttons, one for each possible value.

This is generally used for enumerations, but could also work for any type with a set of possible values. (A simple string can use this look as long as you supply possible values).


propEnum = AppendProperty(parentEnum, id, "Radio", this, "MyProperty", "");
propEnum.Property.Look = new PropertyRadioButtonLook();

It is not necessary to set the height multiplier. The library deduces this from the possible displayed values attached to the Property.

# > PropertyUnitLook

Displays a value and its unit as a single string.

When the Property is selected, the FeelEditUnit inplace control shows a textbox for a numerical value and a combobox for its unit. When it is not selected, the value and its unit must be displayed as a single string, which is what this look does.


propEnum = AppendProperty(parentCategory, id, "Frequency", this, "MyFreq", "");
propEnum.Property.AddValue(PropertyUnitLook.UnitValue, this, "MyUnit", null);
propEnum.Property.Look = new PropertyUnitLook();
propEnum.Property.Feel = GetRegisteredFeel(PropertyGrid.FeelEditUnit);

The look is assigned to the Property, but in order to work, must be aware of the Unit value. The AddValue call does this, and passes a predefined identifier PropertyUnitLook.UnitValue linking the Property to the MyUnit enumeration property.

# Creating your own Look classes

When creating your own Look classes, you may find it helpful to base your code on SPG's existing PropertyLook classes.
You can register your new class with SPG so that it will be automatically selected for Properties of a certain type.


RegisterLookAttachment(typeof(Pen), typeof(PropertyPenLook));
Last Updated: 5/25/2022, 1:18:09 PM