Updating the Smart tag panel of a WebControl requires closing and reopening the panel

The problem

I came across the following scenario a while back: A customer was creating a custom WebControl in the Visual Web Designer. The control had a smart tag panel with an option that they wanted to behave like a radio button. I.e. The text says “Enabled”, you click it and it changes to “Disabled”. The problem was that the panel didn’t refresh. Even if they called DesignerActionUIService.Refresh(). They had to close the panel and reopen it for the change to become visible.

If they instead hosted the same code in a WinForms control then the panel was refreshed immediately. So in effect the code below would update immediately if designing a WinForms component, and require closing and reopening the panel if designing a WebForms panel.

 public bool LockColors
{
    get
    {
        return colLabel.ColorLocked;
    }
    set
    {
        GetPropertyByName("ColorLocked").SetValue(colLabel, value);

        // Refresh the list.
        this.designerActionUISvc.Refresh(this.Component);
    }
}

Cause

Simply put, the Web Developer doesn’t subscribe to the DesignerActionUIStateChange event, so this is currently by design.

Resolution

You can fix this by implementing your own event using code like this:

 public UserControlDesignerActionList(ISourceControlledItem scItem)
        : base(((IDesigner)scItem).Component)
    {
        this.designerActionUISvc = GetService(typeof(DesignerActionUIService))
as DesignerActionUIService;
 
        if (this.Component is Control) {
            this.designerActionUISvc.DesignerActionUIStateChange += 
new DesignerActionUIStateChangeEventHandler(OnDesignerActionUIStateChange);
        }
    }
 
    void OnDesignerActionUIStateChange(object sender, DesignerActionUIStateChangeEventArgs e) {
        if (e.ChangeType == DesignerActionUIStateChangeType.Refresh) {
            ElementDesigner ed = ElementDesigner.GetElementDesigner((Control)this.Component);
            IWebElementDesigner wed = (IWebElementDesigner)ed;
            if (wed != null) {
                wed.UpdateView();
            }
        }
    }

In order for this to work you need to add a reference to Microsoft.Web.Design.Client.dll, which is located at C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE\Microsoft.Web.Design.Client.dll as well as in the Global Assembly Cache.

Licensing

The main issue with this approach is that of licencing. If you intend to redistribute this component to a customer you may redistribute the .dll to that customer if they already own a valid license of that same .dll. Any component you design that need this change to work would require a copy of Visual Studio to be at all usefull, but you never know...

The best approach would probably be to rely on the version in the GAC and not distribute the .dll at all.