.netwinformscontrolsdesign-time

Update Visual Studio Property grid when a Control referenced in another control is removed from the Form


My custom WinForms control has a property used to select another control on the form. Here is a simplified example of such a property:

private TextBox _targetControl;

public TextBox TargetControl
{
    get {return _targetControl;}
    set {_targetControl = value;}
}

If I selected a TextBox control in the TargetControl property of my custom control and then removed the selected TextBox control from the form, the value of the TargetControl property in the property grid becomes empty as expected. But I still can click the plus button in front of the property name and see the properties of the deleted control:

enter image description here

Is there a way to update the property grid to remove that plus button after deleting the selected control?

P.S. This question is related to my previous question regarding getting a notification when a control referenced in another control is removed from the form. I know how to receive a notification when a control is deleted but have no idea how to update the property grid after that.


Solution

  • In relation to the previous question:
    Get design-time notifications when a Control referenced in another control is removed from the Form

    The IComponentChangeService interface allows to receive design-time notifications when a Component (any Component / Control) is added / removed / renamed or changed. The Component can be child of the Form itself or any other child Container).

    Since we're assigning, at design-time, a Component reference to a Property of another Component - so it's shown in the PropertyGrid - we are also caching the object's Properties.
    When the Component is removed from the Form (e.g., deleted), the cached elements are still there.

    To refresh the view in the PropertyGrid, is enough to set the Property that referenced the now removed Component to null.
    This causes the PropertyGrid to read again the Properties' values (all of them) and reset the view.

    public partial class UCComponentsChange : UserControl {
        private IComponentChangeService componentChangeService;
    
        private Control _targetControl = null;
        public Control TargetControl {
            get => _targetControl;
            set => _targetControl = value;
        }
    
        public override ISite Site {
            get => base.Site;
            set {
                base.Site = value;
                RegisterComponentsChangeNotifications();
            }
        }
    
        private void RegisterComponentsChangeNotifications() {
            // [...]
            componentChangeService = GetService(
                typeof(IComponentChangeService)) as IComponentChangeService;
            if (componentChangeService != null) {
                // [...]
            }
        }
    
        private void NotifyComponentRemoved(object sender, ComponentEventArgs e) {
            if (IsTargetControlAffected(e.Component)) {
                // Our Control has been removed. Set the reference to null 
                TargetControl = null;
            }
        }
    
        private bool IsTargetControlAffected(IComponent component) =>
            _targetControl != null && _targetControl == component;
    }