# 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:
- Determines if the Property has an attached UITypeEditor.
- Determines if the value has an attached ImageList.
- 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.
Notes
- 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.
Note
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.
Example:
This example makes full use of the PropertyLook attribute:
[PropertyLook(typeof(PropertyPenLook))]
[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.
Example:
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).
Example:
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.
Example:
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.
Example:
RegisterLookAttachment(typeof(Pen), typeof(PropertyPenLook));