# Events and Virtual Methods

The framework provides several events and virtual methods. These notify listeners or your class derived from PropertyGrid of various important events occurring in the system.

When an event is related to a particular Property (which is generally the case), the argument of the event contains a reference to an enumerator.

# SelectedObjectChanging

Triggered when SelectedObject(s) has been called but before the target instance(s) has actually been changed.

There is a corresponding virtual method:

protected override void OnSelectedObjectChanging(EventArgs e)
{
    // Add your code here...
    base.OnSelectedObjectChanging(e);
}

# SelectedObjectChanged

Triggered after SelectedObject(s) has been called.

There is a corresponding virtual method. The passed argument contains a reference (PreviousTargets) to the previous target instance(s) before the change.

protected override void OnSelectedObjectChanged(SelectedObjectChangedEventArgs e)
{
    // Add your code here...
    base.OnSelectedObjectChanged(e);
}

# PropertyCreated

  • Triggered on creation of a Property.
  • Triggered for child Properties, then parent Properties.

This gives you the opportunity to further set the behaviour and appearance of a Property and its descendents.

There is a corresponding virtual method:

protected override void OnPropertyCreated(PropertyCreatedEventArgs e)
{
    // Add your code here...
    base.OnPropertyCreated(e);
}

Example:

The SPG library does not have yet an attribute to set the description of Properties returned by a TypeConverter. Suppose that you create one derived from DescriptionAttribute and call it DescriptionForChildAttribute (the code for this is not shown here). You intend to use this attribute on complex properties like this:

[DescriptionForChild("GdiVerticalFont", "Indicates whether this Font is derived from a GDI vertical font")]
public Font MyFont
{

You then decide to modify the description of any Property whose parent has the new attribute. The solution is to write a generic piece of code that will work for every Property that you create:

protected override void OnPropertyCreated(PropertyCreatedEventArgs e)
{
    Property parentProperty = e.PropertyEnum.Parent.Property;
    if ((parentProperty != null) && (parentProperty.Value != null))
    {
        List<Attribute> attrs = parentProperty.Value.
            GetAttributes(typeof(DescriptionForChildAttribute));
        foreach (DescriptionForChildAttribute attr in attrs)
        {
            Property property = e.PropertyEnum.Property;
            if (attr.ChildPropertyName == property.Name)
            {
                property.Comment = attr.Description;
                break;
            }
        }
    }
    base.OnPropertyCreated(e);
}

This code:

  1. Checks a new Property's parent to see if it contains the new attribute.
  2. If successful, loops through the attributes (because there can be multiple attributes for several child Properties).
  3. If an attribute corresponds to the name of the current processed Property, applies the new comment (called Description in the MSPG).

# PropertyRestored

Triggered when the states of a property have been restored.

In various circumstances, Properties are internally recreated. When this happens, after a Property has been recreated, its previous states (expanded, selected, colors, etc) are reassigned. This is done in the PropertyGrid.RestorePropertiesStates method (which you can also call manually as explained in section 2.3.1 TODO). This event allows you to be notified when states have been applied so that you could override some of them.

There is a corresponding virtual method:

protected override void OnPropertyRestored(PropertyRestoredEventArgs e)
{
    // Act on a property here
    base.OnPropertyRestored(e);
}

# PropertyValueAttributesNeeded

When SelectedObject(s) is used, it can be difficult to decorate the target instance(s) and/or the published properties with attributes, especially if some parts of the code are not accessible. This event is triggered as soon as the property has been created and inserted in the grid (therefore you can rely on the parent or previous published siblings but not descendants or next published siblings), allowing you to supply your custom attributes. For example, you could pass the ShowChildProperties attributes here, so that it will be taken into account during the continuation of the property creation process.

Notice that some attributes, which must be used by SPG prior to this event (like SortedPropertyAttribute or BrowsableAttribute), can’t be set to the property at this point.

There is a corresponding virtual method:

protected override void
OnPropertyValueAttributesNeeded(PropertyValueAttributesNeededEventArgs e)
{
    // Set e.Attributes here
    base. OnPropertyValueAttributesNeeded(e);
}

# PropertyPreFilterOut

By default, the library filters out those properties with an attached BrowsableAttribute set to false. This event allows the client application to use its own criteria to filter the properties before they are created.

  • Triggered for the Properties created when using SelectedObject(s), only.
  • Sub Properties returned by a TypeConverter are ignored.

There is a corresponding virtual method:

protected override void OnPropertyPreFilterOut(PropertyPreFilterOutEventArgs e)
{
    // Add your code here...
    base.OnPropertyPreFilterOut(e);
}

The argument gives access to the new property's PropertyDescriptor. It also contains a property called FilterOut, which the client application can use to specify whether or not SPG filters out the new Property. This can take one of the following possible values:

Value Effect on property
FilterDefault Filtered out only if it has an attached BrowsableAttribute set to false.
FilterOut Filtered out.
DontFilter Not filtered out, even if it has an attached BrowsableAttribute set to false.

# PropertyPostFilterOut

Gives the client application the opportunity to filter out some Properties of the grid after they are created.

  • Triggered for the Properties created when using SelectedObject(s) only.
  • Sub Properties returned by a TypeConverter are ignored.

Use the FilterOut = true to delete the new Property.

There is a corresponding virtual method:

protected override void OnPropertyPostFilterOut(PropertyPostFilterOutEventArgs e)
{
    // Add your code here...
    base.OnPropertyPostFilterOut(e);
}

Good to know

To prevent a Property from being created in the first place, set BrowsableAttribute to false, or use the PropertyPreFilterOutEvent with your own criteria. The advantage of PropertyPostFilterOutEvent is that you can refer to the Property with an enumerator (since it has been already created) and then delete it based on criteria such as location in the hierarchy, value, name, etc.

# PropertySelected

Triggered on selection of a Property.

There is a corresponding virtual method:

protected override void OnPropertySelected(PropertySelectedEventArgs e)
{
    // Add your code here...
    base.OnPropertySelected(e);
}

# PropertyExpanded

Triggered on expansion or collapse of a Property.

There is a corresponding virtual method:

protected override void OnPropertyExpanded(PropertyExpandedEventArgs e)
{
    // Add your code here...
    base.OnPropertyExpanded(e);
}

# PropertyEnabled

Triggered on disabling or enabling a Property.

There is a corresponding virtual method:

protected override void OnPropertyEnabled(PropertyEnabledEventArgs e)
{
    // Add your code here...
    base.OnPropertyEnabled(e);
}

# PropertyChanging

Triggered when the user has changed a value in the grid and the target properties are about to be updated.

The event arguments parameter has a Cancel property so that it’s possible to stop the committing process. The committed property value can also be overridden by changing the NewValue property.

There is a corresponding virtual method:

protected override void OnPropertyChanging(PropertyChangingEventArgs e)
{
    // Add your code here...
    base.OnPropertyChanging(e);
}

# PropertyChanged

Triggered when the value of a Property in the grid changes.

This is triggered once the end-user has successfully used an inplace control to modify the underlying value of a Property.

Note

This is one of the most important events in the SPG framework.

There is a corresponding virtual method:

protected override void OnPropertyChanged(PropertyChangedEventArgs e)
{
    // Add your code here...
    base.OnPropertyChanged(e);
}

An important feature is the way this virtual method can act on other Properties in the grid. How you use it depends on your application. For example, you may want to disable a Property's children when its value is set to false.

Example:

This disables all children of a Property when its boolean value is set to false:

protected override void OnPropertyChanged(PropertyChangedEventArgs e)
{
    if (e.PropertyEnum.Property.Id == 1000)
    {
        bool value = e.PropertyEnum.Property.Value.GetValue();

        PropertyEnumerator propEnum = e.PropertyEnum.Children;
        propEnum.RestrictedToThisLevelAndUnder = true;
        while (propEnum != propEnum.RightBound)
        {
            EnableProperty(propEnum, value);
            propEnum.MoveNext();
        }
    }

    base.OnPropertyChanged(e);
}

# > Useful PropertyChangedEventArgs arguments

Property Description
SelectedIndex Index of item selected from a list (if applicable).
AdditionalValueKey Identifier of modified value if it is the additional, rather than primary value of the Property. See Multiple values per Property.

Tips

Tip Description
The new value e.PropertyEnum.Property.Value.GetValue()
The previous value e.PropertyEnum.Property.Value.PreviousValue
Use PropertyValue.PreviousValueValid to find out whether the previous value was undefined. This is useful, e.g., when the Property points to multiple Properties in multiple target instances.
The PropertyDescriptors of the value (if any) e.PropertyEnum.Property.Value.PropertyDescriptor(s)

# ValueValidation

Triggered when a user-entered string cannot validate, or when, after it did not validate, it subsequently validates.

For detailed discussion of the value validation mechanism, please see Validating the values.

There is a corresponding virtual method:

protected override void OnValueValidation(ValueValidationEventArgs e)
{
    // Add your code here...
    base.OnValueValidation(e);
}

# InPlaceCtrlVisible

Triggered when an inplace control becomes visible.

An inplace control appears on selection of a Property with an editable value, or on selection of a Property where a read-only value is available for selection and copying.

This event allows you to customize the way an inplace control works. You may have to repeat the customization every time the control becomes visible, because inplace controls are singletons.

Good to know

Inplace controls are singletons in the SPG library. This avoids creating and keeping all the controls for the grid's Properties in memory.

There is a corresponding virtual method:

protected override void OnInPlaceCtrlVisible(InPlaceCtrlVisibleEventArgs e)
{
    // Add your code here...
    base.OnInPlaceCtrlVisible(e);
}

Example:

Because a single up/down inplace control instance edits two Property values, it must be configured each time it appears for one of the two Properties:

protected override void OnInPlaceCtrlVisible(InPlaceCtrlVisibleEventArgs e)
{
    if (e.PropertyEnum.Property.Id == 1000)
        ((PropInPlaceUpDown)e.InPlaceCtrl).RealtimeChange = true;
    else if (e.PropertyEnum.Property.Id == 1001)
        ((PropInPlaceUpDown)e.InPlaceCtrl).RealtimeChange = false;

    base.OnInPlaceCtrlVisible(e);
}

# InPlaceCtrlHidden

Triggered when an inplace control becomes hidden.

This is the simpler counterpart of InPlaceCtrlVisibleEvent, and requires no special actions.

There is a corresponding virtual method:

protected override void OnInPlaceCtrlHidden(InPlaceCtrlHiddenEventArgs e)
{
    // Add your code here...

    base.OnInPlaceCtrlHidden(e);
}

# InPlaceCtrlCreated

Triggered when an inplace control is created or recalled, before becoming visible.

This event is offered for the same reasons as the InPlaceCtrlVisibleEvent. It intervenes before the inplace control is visible, enabling you to make any configuration changes to the control that would recreate its handle.

There is a corresponding virtual method:

protected override void OnInPlaceCtrlCreated(InPlaceCtrlCreatedEventArgs e)
{
    // Add your code here...
    base.OnInPlaceCtrlCreated(e);
}

# PropertyUpDown

Triggered when the user clicks on the arrows of an inplace control, or hits the up and down keys.

This allows you to specify a new value for the control.

There is a corresponding virtual method:

protected override void OnPropertyUpDown(PropertyUpDownEventArgs e)
{
    // Add your code here...
    base.OnPropertyUpDown(e);
}

The argument contains:

  • Value: the current value (as a string) of the Property. Modify this to set a new value.
  • ButtonPressed: indicates what arrow has been pressed.

Example:

protected override void OnPropertyUpDown(PropertyUpDownEventArgs e)
{
    if (e.PropertyEnum.Property.Id == 1000)
    {
        e.Value = (Double.Parse(e.Value) +
            (e.ButtonPressed == PropertyUpDownEventArgs.UpDownButtons.Up ?
                0.05: -0.05)).ToString();
    }

    base.OnPropertyUpDown(e);
}

# PropertyButtonClicked

Triggered when the user clicks the button of a FeelButton or FeelEditButton inplace control.

There is a corresponding virtual method:

protected override void OnPropertyButtonClicked(PropertyButtonClickedEventArgs e)
{
    // Add your code here...
    base.OnPropertyButtonClicked(e);
}

The typical use is to display a custom modal form for entering a new Property value. On closing the form, you must tell the framework if the value has actually changed. Do this by setting PropertyButtonClickedEventArgs’s PropertyChanged to true (Typically, the value changes when the user clicks OK).

# DisplayedValuesNeeded

Triggered on creation of a property.

This event enables you to modify the set of possible values displayed by an inplace control at runtime.

There is a corresponding virtual method:

protected override void OnDisplayedValuesNeeded(DisplayedValuesNeededEventArgs e)
{
    // Set e.DisplayedValues…
    base.OnDisplayedValuesNeeded(e);
}

When a list of strings or objects is supplied, use the DisplayedValues property of the event arguments. When a pair of <object, string> is supplied, use the DisplayedValuePairs property instead.

Examples:

The following modifies a boolean which has default true/false strings:

protected override void OnDisplayedValuesNeeded(DisplayedValuesNeededEventArgs e)
{
    if (e.PropertyEnum.Property.Id == 1000)
        e.DisplayedValues = new string[] { "Enabled", "Disabled" };

    base.OnDisplayedValuesNeeded(e);
}

This other example publishes possible values for planets like in a previous example:

protected override void OnDisplayedValuesNeeded(DisplayedValuesNeededEventArgs e)
{
    if (e.PropertyEnum.Property.Id == 1000)
        e.DisplayedValuePairs = new object[] {
            new Planet(1), "Mercury",
            new Planet(2), "Venus",
            new Planet(3), "Earth",
            new Planet(4), "Mars",
            new Planet(5), "Jupiter",
            new Planet(6), "Saturn" };

    base.OnDisplayedValuesNeeded(e);
}

Consult the section Handling the PropertyValue’s displayed values to know more about the various ways to set and reset the possible values of a Property.

# HyperLinkPropertyClicked

Triggered by the user clicking:

  • A Property created by a call to AppendHyperLinkProperty .
  • A Property with a HyperlinkFormat set.

There is a corresponding virtual method:

protected override void OnHyperLinkPropertyClicked(PropertyHyperLinkClickedEventArgs e)
{
    // Add your code here...
    base.OnHyperLinkPropertyClicked(e);
}

If the Property is a regular Property with a value, you can read the hyperlinked value modified by the string hyperlink format using PropertyHyperLinkClickedEventArgs.HyperLink. (For static hyperlinks, this property equals an empty string.)

# DisplayModeChanged

Triggered when the display mode (Categorized, Flat, FlatSorted) changes.

There is a corresponding virtual method:

protected override void OnDisplayModeChanged(EventArgs e)
{
    // Add your code here...
    base.OnDisplayModeChanged(e);
}

# DrawingManagerChanged

Triggered when the drawing manager changes.

This is used whenever the new drawing manager must be configured.

There is a corresponding virtual method:

protected override void OnDrawingManagerChanged(EventArgs e)
{
    // Add your code here...
    base.OnDrawingManagerChanged(e);
}

Example:

This sets some properties of the LightColorDrawManager when it is applied to the grid:

protected override void OnDrawingManagerChanged(EventArgs e)
{
    if (DrawingManager == DrawManagers.LightColorDrawManager)
    {
        LightColorDrawManager manager = DrawManager as LightColorDrawManager;
        manager.SetCategoryBackgroundColors(
            Color.FromArgb(213, 224, 239), Color.White);
        manager.SetSubCategoryBackgroundColors(
            Color.FromArgb(213, 239, 224), Color.White);
    }

    base.OnDrawingManagerChanged(e);
}

# MouseEnterProperty

Triggered when the mouse enters anywhere in a Property row.

With this event, the application will always know where the mouse is located. One possible application is when you want to create a hover effect

There is a corresponding virtual method:

protected override void OnMouseEnterProperty(SPGMouseEventArgs e)
{
    // Add your code here...
    base.OnMouseEnterProperty(e);
}

Example:

This modifies some colors of the hovered property:

protected override void OnMouseEnterProperty(SPGMouseEventArgs e)
{
    e.PropertyEnumerator.Property.BackColor = _hoveredPropertyBackColor;
    if (e.PropertyEnumerator.Property.Value != null)
        e.PropertyEnumerator.Property.Value.BackColor = GridBackColor;
    base.OnMouseEnterProperty(e);
}

# MouseLeaveProperty

Triggered when the mouse leaves a Property row.

With this event, the application will always know where the mouse is located. One possible application is when you want to create a hover effect.

There is a corresponding virtual method:

protected override void OnMouseLeaveProperty(SPGMouseEventArgs e)
{
    // Add your code here...
    base.OnMouseLeaveProperty(e);
}

Example:

This modifies some colors of the hovered property:

protected override void OnMouseLeaveProperty(SPGMouseEventArgs e)
{
    e.PropertyEnumerator.Property.BackColor = Color.Empty;
    if (e.PropertyEnumerator.Property.Value != null)
        e.PropertyEnumerator.Property.Value.BackColor = Color.Empty;
    base.OnMouseLeaveProperty(e);
 }
Last Updated: 5/25/2022, 1:18:09 PM