One thing that really bugs me with Visual Studio and the way the designers work is that it's often pretty complicated to force the designer to update itself and persist changes in the designer to the underlying code. This is true in both WinForms and ASP.NET.

 

I'm working on a set of ASP.NET server controls that are extenders and the 'ExtenderItems' are shown in the property sheet and can be edited. When you make a change to a property though, those changes are not automatically persisted back into the source view even though you are talking to a live instance of one of the collection items.

 

To make the designer refresh is a bit of a pain – you basically have to manually force the designer to refresh itself. To do this I have to create a method like this on the Extender control (the 'host' control for the extended properties):

 

/// <summary>

/// this method is used to ensure that designer is notified

/// every time there is a change in the sub-ordinate validators

/// </summary>

internal void NotifyDesigner()

{          

    if (this.DesignMode)

    {

        IDesignerHost Host = this.Site.Container as IDesignerHost;

        ControlDesigner Designer = Host.GetDesigner(this) as ControlDesigner;

        PropertyDescriptor Descriptor = null;

        try

        {

            Descriptor = TypeDescriptor.GetProperties(this)["DataBindingItems"];

        }

        catch (Exception ex)

        {

            return;

        }

 

        // *** This works too

        //object Val = pd.GetValue(this);

        //pd.SetValue(this,"___");

        //pd.SetValue(this, Val);

 

        ComponentChangedEventArgs ccea = new ComponentChangedEventArgs(

                    this,

                    Descriptor,

                    null,

                    this.DataBindingItems);

        Designer.OnComponentChanged(this, ccea);

    }

}

 

That's not too bad once you figure this out (with a lot of help from this article from Alex Soldatov). I spent a few hours scouring MSDN for any information on this before running into his article that also helped with a number of other issues that I'm working on.

 

But the real pain is that you now have to call this notification method for every change that's been made to a property of the child items. So the property implementation for any designer properties that can be set for the child properties (DataBindingItems in this case) looks like this:

 

/// <summary>

/// The name of the Object or DataSet/Table/Row to bind to.

/// Page or Container relative. Example: Customer.Entity = this.Customer.Entity

/// </summary>

[NotifyParentProperty(true)]

[Description("The name of the object or DataSet/Table/Row to bind to. Page relative. Example: Customer.DataRow = this.Customer.DataRow"),DefaultValue("")]

public string BindingSource

{

    get { return _BindingSource; }

    set

    {  

        _BindingSource = value;

        if (this.DesignMode && this.Binder != null)

            this.Binder.NotifyDesigner();

    }

}

private string _BindingSource = "";

 

So this sort of code has to be attached to any of the child controls that display in the designer for DataBindingItems.

 

While this doesn't look too bad, it's actually a bit of work to get a reference to the Binder object (the Parent Collection) which in this case is the top level Extender control. I talked about this a couple of days ago – getting a reference to the parent is not trivial in a child collection that is persisted through the designer because ASP.NET and the designer are not firing the standard Add methods on the collection child controls. The only way I was able to make this work is by implementing a custom collection rather than using the easier Generic Collection and overriding the Add method to pass an explicit reference down to the child item.

 

 

It sure would be nice if there was a way to do this with an attribute. It actually looks like this should be happening anyway with the [NotifyParentProperty(true)] but that doesn't appear to have any effect on forcing the designer to dump the values into the HTML source.