August 2007 Entries
You may notice over time that your IPod earbuds get quieter and quieter. You are not necessarily going deaf, it may be the unpleasant buildup of ear wax inside the grill of the earbud itself. If you wear them while working outside in the summer or while working out this is even more likely to occur. I build a paver patio during the summer and this happened. At first I assumed that rubbing alchohol would take care of it but it did very little. Soaked generously into a cotton swab it seemed the best approach but had little effect. I trashed 4 sets of earbuds over time due to the inability to prevent this effect. Just by chance I tried Windex (Ammonia Free) on a cotton swab and noticed that it almost immediately discolored, something that did not happen with 91% isopropyl alchohol. I tried a few more swabs soaked with Windex on the earbuds, dried the earbuds off with dry swabs and paper towels and then tried them out. I got greater results with just 2 swabs than the entire time I tried alchohol.

I have often run into issues with references to the internal class System.Web.SR so I extracted it and corrected the references, then made everything public. It is called PSR and you can find it here: PSR.zip 

*NOTE: This has not yet been tested. Several people have expressed interest in it and I wanted to throw it out there ASAP. Let me know how it works out. I will be testing it at the end of the Delete Verb portion of the current project since there are several references to it therein.

Normally I believe that the Delete View is only available within Design View. There are several possible angles that I am pursuing for exposing the delete verb within the Browse View. One thing to note is that no webparts or user controls can be declared within the page code. All must be added from a catalog to the shared view or the delete function is unavailable. I am researching overriding RenderVerbs and RenderVerb within the WebPartChrome to add the Delete Verb despite Browse being the current view. Failing this I intend to take a brief look at writing a custom view to expose Delete natively, this would be nice since I may be able to expose the Move action as well during the default (then Custom) View. I have a couple of other ideas but I want to see how these turn out first. I am working toward the most effecient way to accomplish the task without having to rewrite tons of functionality. It may be as simple as overriding the close action or something of that nature. We shall see.

Of course many will suggest that none of this is the right way to do things since it is not supported by Microsoft but since I have rewritten much of the WebPart functionality already, it may be considerably easier in this case.

I am including the CustomWebPartZone code as well as the CustomWebPartChrome since it really serves no other purpose than to hijack the call to the standard WebPartChrome and directs the request to CustomWebPartChrome.

 public class CustomWebPartZone : WebPartZone
{
protected override WebPartChrome CreateWebPartChrome()
{return new CustomWebPartChrome(this, base.WebPartManager);}

protected override void OnInit ( EventArgs e ) {}
}


public class CustomWebPartChrome : WebPartChrome
{
private WebPartZone thisZone;
private WebPartManager thisMgr;

public CustomWebPartChrome(WebPartZone zone, WebPartManager mgr) : base(zone, mgr)
{
thisZone = zone;
thisMgr = mgr;
}

private double duration;
protected internal double Duration
{
get { return duration; }
set { duration = value; }
}

public override void PerformPreRender()
{
base.PerformPreRender();

string js = "<script language='javascript'>\n\t" +
"var titleBar;\n";

foreach (WebPart webPart in Zone.WebParts)
{
js += ("titleBar = document.getElementById('" + GetWebPartTitleClientID(webPart) + "');\n");
js += "titlebar.onmouseover = ShowNote;\n";
js += "titlebar.onmouseout = HideNote;\n";
}

js += "</script>";
// thisZone.Page.ClientScript.RegisterStartupScript(typeof(CustomWebPartChrome), typeof(CustomWebPartChrome).FullName, js);
// thisZone.Page.ClientScript.RegisterClientScriptInclude(typeof(CustomWebPartChrome).FullName, "CustomWebPartChrome.js");
}

public void renderTitleBar ( HtmlTextWriter writer, WebPart webPart )
{
writer.AddAttribute ( HtmlTextWriterAttribute.Cellspacing, "0" );
writer.AddAttribute ( HtmlTextWriterAttribute.Cellpadding, "0" );
writer.AddAttribute ( HtmlTextWriterAttribute.Border, "0" );
writer.AddStyleAttribute ( HtmlTextWriterStyle.Width, "100%" );
writer.RenderBeginTag ( HtmlTextWriterTag.Table );
writer.RenderBeginTag ( HtmlTextWriterTag.Tr );
writer.AddAttribute ( HtmlTextWriterAttribute.Alt, "Rendering Verbs" );
writer.RenderBeginTag ( HtmlTextWriterTag.Td );
typeof ( WebPartChrome ).GetMethod ( "RenderVerbsInTitleBar", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance ).Invoke ( this, new object[] { writer, webPart, 1 } );
writer.RenderEndTag ();

writer.AddStyleAttribute ( HtmlTextWriterStyle.Width, "100%" );
TableItemStyle partTitleStyle = thisZone.PartTitleStyle;
writer.AddStyleAttribute ( HtmlTextWriterStyle.WhiteSpace, "nowrap" );
writer.AddAttribute ( HtmlTextWriterAttribute.Align, "left");
writer.AddAttribute ( HtmlTextWriterAttribute.Valign, "top");
writer.AddAttribute ( HtmlTextWriterAttribute.Id, base.GetWebPartTitleClientID ( webPart ) );

writer.RenderBeginTag ( HtmlTextWriterTag.Td );
typeof ( WebPartChrome ).GetMethod ( "RenderTitleText", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance ).Invoke ( this, new object[] { writer, webPart} );
writer.RenderEndTag ();
writer.RenderEndTag ();
writer.RenderEndTag ();
}


public override void RenderWebPart ( HtmlTextWriter writer, WebPart webPart )
{
if ( webPart == null )
{
throw new ArgumentNullException ( "webPart" );
}
bool flag = true;
PartChromeType chromeType = thisZone.GetEffectiveChromeType ( webPart );

Style style = base.CreateWebPartChromeStyle ( webPart, chromeType );
if ( !style.IsEmpty )
{
style.AddAttributesToRender ( writer, thisZone );
}
writer.AddAttribute ( HtmlTextWriterAttribute.Cellspacing, "0" );
writer.AddAttribute ( HtmlTextWriterAttribute.Cellpadding, "0" );
writer.AddAttribute ( HtmlTextWriterAttribute.Border, "0" );
writer.AddAttribute ( HtmlTextWriterAttribute.Alt, "Render Web Part" );
writer.AddStyleAttribute ( HtmlTextWriterStyle.Width, "100%" );
if ( webPart.ChromeState != PartChromeState.Minimized )
{
writer.AddStyleAttribute ( HtmlTextWriterStyle.Height, "100%" );
}
writer.AddAttribute ( HtmlTextWriterAttribute.Id, base.GetWebPartChromeClientID ( webPart ) );

if ( ( webPart.Hidden ) && ( ( thisMgr != null ) && !thisMgr.DisplayMode.ShowHiddenWebParts ) )
{
writer.AddStyleAttribute ( HtmlTextWriterStyle.Display, "none" );
}
writer.RenderBeginTag ( HtmlTextWriterTag.Table );
writer.RenderBeginTag ( HtmlTextWriterTag.Tr );
writer.AddAttribute ( HtmlTextWriterAttribute.Alt, "Rendering Titlebar Cell" );
writer.RenderBeginTag ( HtmlTextWriterTag.Td );
renderTitleBar ( writer, webPart );
writer.RenderEndTag ();
writer.RenderEndTag ();

if ( webPart.ChromeState == PartChromeState.Minimized )
{
writer.AddStyleAttribute ( HtmlTextWriterStyle.Display, "none" );
}
writer.RenderBeginTag ( HtmlTextWriterTag.Tr );
if ( !flag )
{
writer.AddStyleAttribute ( HtmlTextWriterStyle.Height, "100%" );
writer.AddAttribute ( HtmlTextWriterAttribute.Valign, "top" );
}
Style partStyle = thisZone.PartStyle;
if ( !partStyle.IsEmpty )
{
partStyle.AddAttributesToRender ( writer, thisZone );
}
writer.AddStyleAttribute ( HtmlTextWriterStyle.Padding, "0px" );
writer.AddAttribute ( HtmlTextWriterAttribute.Alt, "Rendering Part Contents" );
writer.RenderBeginTag ( HtmlTextWriterTag.Td );
base.RenderPartContents ( writer, webPart );
writer.RenderEndTag ();
writer.RenderEndTag ();
writer.RenderEndTag ();
}
}

Source for CustomCatalogPartChrome referenced from CustomCatalogZone

 /// <summary>
/// Summary description for CustomCatalogPartChrome
/// </summary>
public class CustomCatalogPartChrome : CatalogPartChrome
{
private CatalogZone _zone;
private Page _page;

public CustomCatalogPartChrome (CatalogZone zone):base(zone)
{

this._zone = zone;
this._page = zone.Page;
}

public override void RenderCatalogPart ( HtmlTextWriter writer, CatalogPart catalogPart )
{
if ( catalogPart == null )
{
throw new ArgumentNullException ( "catalogPart" );
}
PartChromeType chromeType = this.Zone.GetEffectiveChromeType ( catalogPart );
Style style = base.CreateCatalogPartChromeStyle ( catalogPart, chromeType );
if ( !style.IsEmpty )
{
style.AddAttributesToRender ( writer, this.Zone );
}
writer.AddAttribute ( HtmlTextWriterAttribute.Cellspacing, "0" );
writer.AddAttribute ( HtmlTextWriterAttribute.Cellpadding, "0" );
writer.AddAttribute ( HtmlTextWriterAttribute.Border, "0" );
writer.AddStyleAttribute ( HtmlTextWriterStyle.Width, "100%" );
writer.RenderBeginTag ( HtmlTextWriterTag.Table );
switch ( chromeType )
{
case PartChromeType.TitleOnly:
case PartChromeType.TitleAndBorder:
{
writer.RenderBeginTag ( HtmlTextWriterTag.Tr );
Style partTitleStyle = this.Zone.PartTitleStyle;
if ( !partTitleStyle.IsEmpty )
{
partTitleStyle.AddAttributesToRender ( writer, this.Zone );
}
writer.RenderBeginTag ( HtmlTextWriterTag.Td );
this.RenderTitle ( writer, catalogPart );
writer.RenderEndTag ();
writer.RenderEndTag ();
break;
}
}
if ( catalogPart.ChromeState != PartChromeState.Minimized )
{
writer.RenderBeginTag ( HtmlTextWriterTag.Tr );
Style partStyle = this.Zone.PartStyle;
if ( !partStyle.IsEmpty )
{
partStyle.AddAttributesToRender ( writer, this.Zone );
}
writer.RenderBeginTag ( HtmlTextWriterTag.Td );
this.RenderPartContents ( writer, catalogPart );
typeof ( CatalogPartChrome ).GetMethod ( "RenderItems", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance ).Invoke ( this, new object[] { writer, catalogPart } );
writer.RenderEndTag ();
writer.RenderEndTag ();
}
writer.RenderEndTag ();
}


public void RenderTitle ( HtmlTextWriter writer, CatalogPart catalogPart )
{
Label label = new Label ();
label.Text = catalogPart.DisplayTitle;
label.ToolTip = catalogPart.Description;
label.Page = this._page;
label.RenderControl ( writer );
}
}

Source for a Custom CatalogZone This hijacks the catalogpartchrome and uses a customcatalogpartchrome but has a few other niceties as well.

/// <summary>
/// Summary description for CustomCatalogZone
/// </summary>
public class CustomCatalogZone : CatalogZone
{
// Fields
private ITemplate _zoneTemplate;

protected override CatalogPartChrome CreateCatalogPartChrome ()
{
return new CustomCatalogPartChrome ( this );
}


protected override void RaisePostBackEvent ( string eventArgument )
{
string[] textArray = eventArgument.Split ( new char[] { '$' } );
if ( ( textArray.Length == 2 ) && ( textArray[0] == "select" ) )
{
this.SelectedCatalogPartID = textArray[1];
}
else if ( string.Equals ( eventArgument, "add", StringComparison.OrdinalIgnoreCase ) )
{
if ( this.AddVerb.Visible && this.AddVerb.Enabled )
{
HttpContext.Current.Session["WebPartsAdded"] = true;

typeof ( CatalogZoneBase ).GetMethod ( "AddSelectedWebParts", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance ).Invoke ( this, new object[] { } );

this.Close ();

}
}
else if ( string.Equals ( eventArgument, "close", StringComparison.OrdinalIgnoreCase ) )
{
if ( this.CloseVerb.Visible && this.CloseVerb.Enabled )
{
this.Close ();
}
}
else
{
base.RaisePostBackEvent ( eventArgument );
}
}

protected override void Close ()
{
if ( base.WebPartManager != null )
{
base.WebPartManager.DisplayMode = WebPartManager.BrowseDisplayMode;
}

// HttpContext.Current.Response.Redirect ( "default.aspx" );

}

}

This is the source for a recently created custom declarativecatalogpart that filters out webparts that already exist on the page. This prevents duplicate webparts from being added. Otherwise it will run from either a template control list or declared controls. 

/// <summary>
 /// A replacement for the declarative catalog part meant for limiting the webparts on a page to a single instance by hiding the webparts that already exist on the page.
 /// </summary>
 [Designer ( "System.Web.UI.Design.WebControls.WebParts.DeclarativeCatalogPartDesigner, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" ), AspNetHostingPermission ( SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal ), AspNetHostingPermission ( SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal )]
 public class CustomCatalog : CatalogPart
 {
  // Fields
  private WebPartDescriptionCollection _descriptions;
  private string _webPartsListUserControlPath;
  private ITemplate _webPartsTemplate;
  private Dictionary<string, string> _loadedWebparts;   
  private Dictionary<string, WebPart> _availableWebparts;   // <WebPartDescription.ID, WebPart>

  // Methods
  private void AddControlToDescriptions ( Control control, ArrayList descriptions, Dictionary<string, WebPart> availableWebparts)
  {
   WebPart webPart = control as WebPart;

   if ( ( webPart == null ) && !( control is LiteralControl ))    
     webPart = base.WebPartManager.CreateWebPart ( control );


   if ( ( webPart != null ) && ( ( base.WebPartManager == null ) || base.WebPartManager.IsAuthorized ( webPart ) ) )
   {
    if ( this._loadedWebparts.Count == 0 || this._loadedWebparts == null )
    {
      this.LoadExistingWebParts ();
    }

    WebPartDescription description = new WebPartDescription ( webPart );
    
    if ( !( ((Dictionary<string, string>)HttpContext.Current.Session["loadedWebParts"]).ContainsKey ( description.Title ) ))
    {
      descriptions.Add ( description );
    }
    availableWebparts.Add ( description.ID, webPart );
   }
  }

  public override WebPartDescriptionCollection GetAvailableWebPartDescriptions ()
  {
   if ( this._loadedWebparts == null || this._loadedWebparts.Count == 0 )
   {
     this.LoadExistingWebParts ();
   }
   if ( this._descriptions == null )         
    this.LoadAvailableWebParts ();

   return this._descriptions;
  }

  public override WebPart GetWebPart ( WebPartDescription description )
  {
   if ( description == null )    
    throw new ArgumentNullException ( "description" );


   if ( !this.GetAvailableWebPartDescriptions ().Contains ( description ) )
    throw new ArgumentException ( "CatalogPart_UnknownDescription", "description" );


   ((Dictionary<string, string>)HttpContext.Current.Session["loadedWebParts"]).Add ( description.Title, description.ID );

   
   return this._availableWebparts[description.ID];
  }


  public void LoadExistingWebParts ()
  {
   WebPartDescription description = null;
   if ( HttpContext.Current.Session["loadedWebParts"] != null )
    this._loadedWebparts = ( Dictionary<string, string> ) HttpContext.Current.Session["loadedWebParts"];

   if ( this._loadedWebparts == null || this._loadedWebparts.Count == 0)
    this._loadedWebparts = new Dictionary<string, string> ();

    WebPartCollection webparts = base.WebPartManager.WebParts;
    foreach ( WebPart webPart in webparts )
    {
     description = new WebPartDescription ( webPart );
     if ( !( this._loadedWebparts.ContainsKey ( description.Title ) ) && description.Title != "" )
      this._loadedWebparts.Add ( description.Title, description.ID );

    }
   if(this._loadedWebparts.Count > 0)
    HttpContext.Current.Session["loadedWebParts"] = this._loadedWebparts;
  }


  private void LoadAvailableWebParts ()
  {
   ArrayList descriptions = new ArrayList ();
   Dictionary<string, WebPart> availableWebparts = new Dictionary<string, WebPart> ();

   if ( this.WebPartsTemplate != null )
   {
    Control container = new CustomNonParentingControl ();
    this.WebPartsTemplate.InstantiateIn ( container );
    if ( container.HasControls () )
    {
     Control[] array = new Control[container.Controls.Count];
     container.Controls.CopyTo ( array, 0 );
     foreach ( Control control2 in array )
     {
      this.AddControlToDescriptions ( control2, descriptions, availableWebparts );
     }
    }
   }
   string webPartsListUserControlPath = this.WebPartsListUserControlPath;

   if ( !string.IsNullOrEmpty ( webPartsListUserControlPath ) && !base.DesignMode )
   {
    Control control3 = this.Page.LoadControl ( webPartsListUserControlPath );
    if ( ( control3 != null ) && control3.HasControls () )
    {
     Control[] controlArray2 = new Control[control3.Controls.Count];
     control3.Controls.CopyTo ( controlArray2, 0 );
     foreach ( Control control4 in controlArray2 )
     {
      this.AddControlToDescriptions ( control4, descriptions, availableWebparts );
     }
    }
   }
   this._availableWebparts = availableWebparts;
   this._descriptions = new WebPartDescriptionCollection ( descriptions );
  }


  protected override void Render ( HtmlTextWriter writer )
  {
  }

  #region Properties
  // Properties
  [EditorBrowsable ( EditorBrowsableState.Never ), Themeable ( false ), Browsable ( false )]
  public override string AccessKey
  {
   get
   {
    return base.AccessKey;
   }
   set
   {
    base.AccessKey = value;
   }
  }

  [Themeable ( false ), Browsable ( false ), EditorBrowsable ( EditorBrowsableState.Never )]
  public override Color BackColor
  {
   get
   {
    return base.BackColor;
   }
   set
   {
    base.BackColor = value;
   }
  }

  [Browsable ( false ), Themeable ( false ), EditorBrowsable ( EditorBrowsableState.Never )]
  public override string BackImageUrl
  {
   get
   {
    return base.BackImageUrl;
   }
   set
   {
    base.BackImageUrl = value;
   }
  }

  [Browsable ( false ), EditorBrowsable ( EditorBrowsableState.Never ), Themeable ( false )]
  public override Color BorderColor
  {
   get
   {
    return base.BorderColor;
   }
   set
   {
    base.BorderColor = value;
   }
  }

  [Browsable ( false ), Themeable ( false ), EditorBrowsable ( EditorBrowsableState.Never )]
  public override BorderStyle BorderStyle
  {
   get
   {
    return base.BorderStyle;
   }
   set
   {
    base.BorderStyle = value;
   }
  }

  [Themeable ( false ), EditorBrowsable ( EditorBrowsableState.Never ), Browsable ( false )]
  public override Unit BorderWidth
  {
   get
   {
    return base.BorderWidth;
   }
   set
   {
    base.BorderWidth = value;
   }
  }

  [Themeable ( false ), Browsable ( false ), EditorBrowsable ( EditorBrowsableState.Never )]
  public override string CssClass
  {
   get
   {
    return base.CssClass;
   }
   set
   {
    base.CssClass = value;
   }
  }

  [Themeable ( false ), EditorBrowsable ( EditorBrowsableState.Never ), Browsable ( false )]
  public override string DefaultButton
  {
   get
   {
    return base.DefaultButton;
   }
   set
   {
    base.DefaultButton = value;
   }
  }

  [EditorBrowsable ( EditorBrowsableState.Never ), Browsable ( false ), Themeable ( false )]
  public override ContentDirection Direction
  {
   get
   {
    return base.Direction;
   }
   set
   {
    base.Direction = value;
   }
  }

  [EditorBrowsable ( EditorBrowsableState.Never ), Themeable ( false ), Browsable ( false )]
  public override bool Enabled
  {
   get
   {
    return base.Enabled;
   }
   set
   {
    base.Enabled = value;
   }
  }

  [Browsable ( false ), Themeable ( false ), DefaultValue ( false ), EditorBrowsable ( EditorBrowsableState.Never )]
  public override bool EnableTheming
  {
   get
   {
    return false;
   }
   set
   {
    throw new NotSupportedException ( "Theming Not Supported" );
   }
  }

  [EditorBrowsable ( EditorBrowsableState.Never ), Themeable ( false ), Browsable ( false )]
  public override FontInfo Font
  {
   get
   {
    return base.Font;
   }
  }

  [EditorBrowsable ( EditorBrowsableState.Never ), Browsable ( false ), Themeable ( false )]
  public override Color ForeColor
  {
   get
   {
    return base.ForeColor;
   }
   set
   {
    base.ForeColor = value;
   }
  }

  [Browsable ( false ), Themeable ( false ), EditorBrowsable ( EditorBrowsableState.Never )]
  public override string GroupingText
  {
   get
   {
    return base.GroupingText;
   }
   set
   {
    base.GroupingText = value;
   }
  }

  [Browsable ( false ), Themeable ( false ), EditorBrowsable ( EditorBrowsableState.Never )]
  public override Unit Height
  {
   get
   {
    return base.Height;
   }
   set
   {
    base.Height = value;
   }
  }

  [Browsable ( false ), EditorBrowsable ( EditorBrowsableState.Never ), Themeable ( false )]
  public override HorizontalAlign HorizontalAlign
  {
   get
   {
    return base.HorizontalAlign;
   }
   set
   {
    base.HorizontalAlign = value;
   }
  }

  [Browsable ( false ), Themeable ( false ), EditorBrowsable ( EditorBrowsableState.Never )]
  public override ScrollBars ScrollBars
  {
   get
   {
    return base.ScrollBars;
   }
   set
   {
    base.ScrollBars = value;
   }
  }

  [DefaultValue ( "" ), Themeable ( false ), EditorBrowsable ( EditorBrowsableState.Never ), Browsable ( false )]
  public override string SkinID
  {
   get
   {
    return string.Empty;
   }
   set
   {
    throw new NotSupportedException ( "SkinID Not Supported" );
   }
  }

  [Browsable ( false ), Themeable ( false ), EditorBrowsable ( EditorBrowsableState.Never )]
  public override short TabIndex
  {
   get
   {
    return base.TabIndex;
   }
   set
   {
    base.TabIndex = value;
   }
  }

  [DefaultValueAttribute ( "DeclarativeCatalogPart_PartTitle" )]
  public override string Title
  {
   get
   {
    string text = ( string ) this.ViewState["Title"];
    if ( text == null )
    {
     return "Unknown";
    }
    return text;
   }
   set
   {
    this.ViewState["Title"] = value;
   }
  }

  [Browsable ( false ), EditorBrowsable ( EditorBrowsableState.Never ), Themeable ( false )]
  public override string ToolTip
  {
   get
   {
    return base.ToolTip;
   }
   set
   {
    base.ToolTip = value;
   }
  }

  [EditorBrowsable ( EditorBrowsableState.Never ), Themeable ( false ), Browsable ( false )]
  public override bool Visible
  {
   get
   {
    return base.Visible;
   }
   set
   {
    base.Visible = value;
   }
  }

  [DefaultValue ( "" ), Editor ( "System.Web.UI.Design.UserControlFileEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof ( UITypeEditor ) ), CategoryAttribute ( "Behavior" ), Themeable ( false ), UrlProperty, DescriptionAttribute ( "DeclarativeCatlaogPart_WebPartsListUserControlPath" )]
  public string WebPartsListUserControlPath
  {
   get
   {
    if ( this._webPartsListUserControlPath == null )
    {
     return string.Empty;
    }
    return this._webPartsListUserControlPath;
   }
   set
   {
    this._webPartsListUserControlPath = value;
    this._descriptions = null;
   }
  }

  [TemplateContainer ( typeof ( DeclarativeCatalogPart ) ), Browsable ( false ), DefaultValue ( ( string ) null ), PersistenceMode ( PersistenceMode.InnerProperty )]
  public ITemplate WebPartsTemplate
  {
   get
   {
    return this._webPartsTemplate;
   }
   set
   {
    this._webPartsTemplate = value;
    this._descriptions = null;
   }
  }

  [Themeable ( false ), EditorBrowsable ( EditorBrowsableState.Never ), Browsable ( false )]
  public override Unit Width
  {
   get
   {
    return base.Width;
   }
   set
   {
    base.Width = value;
   }
  }

  [Themeable ( false ), Browsable ( false ), EditorBrowsable ( EditorBrowsableState.Never )]
  public override bool Wrap
  {
   get
   {
    return base.Wrap;
   }
   set
   {
    base.Wrap = value;
   }
  }
  #endregion
 }

 public class CustomNonParentingControl : Control
 {
  protected override void AddedControl ( Control control, int index ){}
  protected override void RemovedControl ( Control control ){}
 }

I have done a considerable amount of work with custom webpart infrastructure over the past weeks and over the next few days will be following that progress and the current progress to add functionality to the Browse View. Most notably I intend to use custom declarative catalog parts for webpart categorization and add actual delete functionality to the Browse View.

So far we have:

We need to add:

  • Custom WebPartManager
  • Custom View based on Browse View
  • Implementation of the Custom WebPartChrome to allow the Delete Verb.

The main purpose of all of this is to add the ability to delete a webpart, and that webpart will return to the custom declarativecatalogpart from whence it came, or simply put, return to its category when deleted. Currently the custom declarativecatalogpart functions so that any webpart already on the page does not show up on the catalog.

More to follow.