Custom web part property editor within web part body 

Tags:

Out of the box SharePoint comes with a lot of Web 2.0 features that empower the end users to customize and personalize their pages and the web parts on those pages.  In WSS v3 much of this power comes from ASP.NET 2.0 and the web part infrastructure including many EditorPart controls found in the System.Web.UI.WebControls.WebParts namespace.  Some of these controls include the AppearanceEditorPart, BehaviorEditorWebPart and LayoutEditorPart all used to define characteristics about how the web part is rendered to the end user.  

Additionally, there is the PropertyGridEditorPart which provides a great deal of power and flexibility to web part developers by allowing them to configure additional web part properties that are persisted to durable storage on either a shared or per user basis.  While, I love this power I didn’t like having a separate zone to edit web part properties.  I felt it would be more user friendly if certain properties were editable within the web part frame rather than in a separate tool part.

Custom Verb in the WebPartVerbsCollection used to initiate an expand of the custom web part properties editor panel. Edit Properties Verb

Expanded web part properties editor panel showing editable properties available for a web partExpanded Properties

Based on the functionality of the PropertyGridEditorPart a base web part was created allowing all inheriting web parts to reap the rewards of an expand/collapse property editor that when wrapped with an Update Panel provides a clean no visible post back way of editing web part properties.  In the code snippets below I have broken down my approach into steps that correlate to the lifecycle of the web part. 

First the controls for each of the properties needed to be created.

In the CreateChildControls override a filtered list of editable properties for the user are retrieved for the web part using GetEditableProperties  method and then controls are created for each of the properties using CreateEditorControl

        protected override void CreateChildControls()

        {

            //... Additional code omitted for clarity

 

            // Clear editor controls before populating

            this.EditorControls.Clear();

 

            // Loop through filtered list of editable properties to generate a property editor control for it

            foreach (PropertyDescriptor descriptor in this.GetEditableProperties(true))

            {

                // Create the control

                Control control = this.CreateEditorControl(descriptor);

 

                if (control != null)

                {

                    // Add to the editor controls array for user later when applying changes and handling errors

                    this.EditorControls.Add(control);

 

                    // Get the display name and description to use for the control label

                    String displayName = this.GetDisplayName(descriptor);

                    String description = this.GetDescription(descriptor);

 

                    // Add the control to the property table with the label and description

                    this.AddControlToPropertiesTable(displayName, description, control);

                }

            }

 

            // Initialize error messages array to the number of editor controls

            this._errorMessages = new String[this.EditorControls.Count];

 

            //... Additional code omitted for clarity

        }

        private PropertyDescriptorCollection GetEditableProperties(bool sort)

        {

            // Get a filtered list of properties

            PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(this,

                new Attribute[] { WebPartBrowsableAttribute.Yes });

 

            // Sort the list if necessary

            if (sort)

            {

                properties = properties.Sort();

            }

 

            // Loop through list of properties and determine if this user can edit (personalizible vs shared)

            PropertyDescriptorCollection descriptors2 = new PropertyDescriptorCollection(null);

            foreach (PropertyDescriptor descriptor in properties)

            {

                if (this.CanEditProperty(descriptor))

                {

                    descriptors2.Add(descriptor);

                }

            }

 

            return descriptors2;

        }

       private Control CreateEditorControl(PropertyDescriptor property)

        {

 

            // Get the type for the property to determine which control to create

            Type propertyType = property.PropertyType;

 

            // Return a CheckBox if the property is a boolean

            if (propertyType == typeof(bool))

            {

                CheckBox checkBox = new CheckBox();

                checkBox.ID = controlId;

                return checkBox;

            }

 

            // Return a DropDownList if the property is an enumeration

            if (typeof(Enum).IsAssignableFrom(propertyType))

            {

                DropDownList list = new DropDownList();

                list.ID = controlId;

 

                // Create the list of enumeration items add populate the DropDownList

                foreach (Object obj in property.Converter.GetStandardValues())

                {

                    String text = property.Converter.ConvertToString(obj);

                    list.Items.Add(new ListItem(text));

                }

                return list;

            }

 

            // Return a TextBox if no other control match was found

            TextBox textbox = new TextBox();

            textbox.ID = controlId;

            textbox.Columns = TextBoxColumns;

 

            return textbox;

           

        }

Now that the controls have been created they need to be populated with values from the web part properties.

In the OnPreRender event which occurs after CreateChildControls() and is a recommended location for your data interaction activities the properties are synced to the controls so when they are rendered they have the updated property information.  If you’ve ever created a custom EditorPart, SyncChanges  will be very familiar since that is a method you override for syncing your properties to your custom controls.

        protected override void OnPreRender(EventArgs e)

        {

            //... Additional code omitted for clarity

 

            // If the web part is visible and there are no errors load property editor controls with their data

            if (this.Visible && !this.HasError)

            {

                this.SyncChanges();

            }

 

            //... Additional code omitted for clarity

        }

 

private void SyncChanges()

        {

            // Make sure the controls exist

            this.EnsureChildControls();

            int num = 0;

 

            // Get all the editable properties and set the control value

            foreach (PropertyDescriptor descriptor in this.GetEditableProperties(true))

            {

                if (this.CanEditProperty(descriptor))

                {

                    // Get the control from the editor controls collection

                    Control control = (Control)this.EditorControls[num];

 

                    // Set the value of the control based on type

                    this.SyncChanges(control, descriptor);

                    num++;

                }

            }

        }

 

        private void SyncChanges(Control control, PropertyDescriptor property)

        {

            if (propertyType == typeof(bool))

            {

                CheckBox box = (CheckBox)control;

                box.Checked = (bool)property.GetValue(this);

            }

            else if (typeof(Enum).IsAssignableFrom(propertyType))

            {

                DropDownList list = (DropDownList)control;

                list.SelectedValue = property.Converter.ConvertToString(property.GetValue(this));

            }

            else

            {

                TextBox box2 = (TextBox)control;

                box2.Text = property.Converter.ConvertToString(property.GetValue(this));

            }

        }

Finally, when you make changes to the property values in the web controls the changes need to be applied to the web part properties.

 In the save event handler  this is accomplished by calling an ApplyChanges method.  Again ApplyChanges comes from its EditorPart roots meaning to apply control changes to the properties.  Within the ApplyChanges method the GetEditableProperties method is used again to retrieve the properties and then an Array of controls populated during CreateChildControls is used to retrieve the control values and set the property value.  Note that much of the error handling and try catch blocks have been removed for clarity.

protected void SaveLinkButton_Click(Object sender, EventArgs e)

        {

            //... Additional code omitted for clarity

 

            // Update the properties

            this.ApplyChanges();

        }

        private bool ApplyChanges()

        {

            //... Additional code omitted for clarity

 

            // Loop through each editible property, get the control for it and set its value

            PropertyDescriptorCollection editableProperties = this.GetEditableProperties(true);

            for (int i = 0; i < editableProperties.Count; i++)

            {

                // Get the property

                PropertyDescriptor property = editableProperties[i];

 

                // Get the editor control

                Control editorControl = (Control)this.EditorControls[i];

 

                // Get the value from the control

                Object editorControlValue = this.GetEditorControlValue(editorControl, property);

 

    property.SetValue(this, editorControlValue);

 

                //... Additional code omitted for clarity

            }

            //... Additional code omitted for clarity

        }

        private Object GetEditorControlValue(Control editorControl, PropertyDescriptor property)

        {

            CheckBox box = editorControl as CheckBox;

            if (box != null)

            {

                return box.Checked;

            }

            DropDownList list = editorControl as DropDownList;

            if (list != null)

            {

                String selectedValue = list.SelectedValue;

                return property.Converter.ConvertFromString(selectedValue);

            }

            TextBox box2 = (TextBox)editorControl;

            return property.Converter.ConvertFromString(box2.Text);

        }

As a part of this exercise a custom attribute was introduced to allow showing properties only in the custom web part properties panel and not in the standard PropertyGridEditorPart the screen shots below demonstrate this.

ShowInWebPartPanel property shows here but the ShowInPropertyGrid property does notFiltered Properties based on custom attribute

ShowInPropertyGrid property shows in the PropertyGridEditorPart but the ShowInWebPartPanel property does notModify Shared Web Part Filtered Properties

 
Posted by Bo George on 10-Jul-07
28 Comments  |  Trackback Url  |  Link to this post | Bookmark this post with:        
 

Links to this post

Comments


Great Solution! commented on Friday, 2-Nov-2007
This is a great solution for creating a customized editor for your web part. Is it possible to get the sample code for this webpart? I would like to implement this solution as well. Thanks, Paul


Re: Great Solution! commented on Monday, 5-Nov-2007
Hi Paul. We did this work for a client and don't feel comfortable showing all of the details for this and I'm afraid we don't have time to completely scrub the code into something that works without showing the client specific portions. We do have a lot of code snippets above, however. Is there any particular portion you are having trouble with?


Good solution but could not figure out how you did it commented on Wednesday, 7-Nov-2007
OnPreRender event and CreateChildControls() should be in your web part or you created your own PropertyGridEditorPart? Thanks, Janne


Re: Good solution but could not figure out how you did it commented on Monday, 12-Nov-2007
We created a BaseWebPart along with a BaseAjaxWebPart. The latter exteded the former. All of our web parts extended one of those two. The BaseWebPart has logic throughout it (includin CreateChildControls()) to render (through reflection) the web part properties in a div that was hidden/shown on command. Note that we had special attributes we could apply to web part properties so we knew how to handle them. One advanced example would tie a property to a web service that was used by an the Auto Complete AJAX toolkit (http://www.asp.net/AJAX/AjaxControlToolkit/Samples/AutoComplete/AutoComplete.aspx).


Could not save the property permantly commented on Tuesday, 13-Nov-2007
Hi Paul, Thanks for answer my question. I really want this could work on my project. The problem I got is I could save the property permantly as did when I used PropertyEditGrid. Every time after the property was saved, I closed the website, and reopen it, the property keep the old value not the value just set. Do you know anyting cause this? Thanks


How ddi you implement the custom attribute commented on Tuesday, 13-Nov-2007
Hi Paul, How did you implement the custom attribute so the property only display on webpart not on propertyEditGrid? Thanks for your helps


I got the same problem that could not save the property permanently commented on Wednesday, 14-Nov-2007
Hi Kirk, Yes, I got same issue that the property value could not save permanently. I just wander that if you had the same error before and how can I fix it. Oh, another question, does this work if the property's attribute is Personal as I had on the following code: [WebBrowsable(false)] [WebPartStorage(Storage.Personal)] [Personalizable(PersonalizationScope.User)] [Description("My Location Test")] public string Location { get { return _location; } set { _location = value; } } Thanks very much for your help, Janne


Maybe some answers :-S commented on Wednesday, 14-Nov-2007
All, Hopefully this helps a little... If you want your property to show in the custom editable properties panel (I guess this is what others mean when with "propertyEditGrid") and not in the miscellaneous section of the SharePoint out of the box properties panel, you need to do two things: 1. Create controls to show in the custom properties panel (e.g., Label, TextBox) - CreateChildControls is a good place for this. 2. Adorn your web part property with [WebBrowseable(false)]. The former shows the controls in the custom editable properties panel. The latter prevents it from showing in the OOTB SharePoint properties panel. Regarding Janne's question around PersonalizationScope.Personal, this can work just fine. We used this on our project. I don't recall using the WebPartStorage attribute, though - just the Personalizable attribute. Creating your own custom .NET attribute classes is useful if you want to provide more information to your base class about a property. For example we used this to give the ability to have simple property use a DropDownList list data that comes from a method that was custom to each web part. The web part would supply the method name in the attribute and our base class would look for that attribute and call the method at the appropriate time. This is a more advanced technique and you'll want to understand how to create your own attribute classes before diving into this. It's not rocket science, but many developers haven't created their own custom attributes before. The code snippets in this blog probably do not show this technique. I think we applied it after the blog was written. I hope this helps! Kirk


I got the same problem that could not save the property permanently commented on Thursday, 15-Nov-2007
I think the property may not be saving permanently because something that I must have neglected from the code sample was to SetDirty on the web part to indicated that properties have changed. I believe if you do that it may make sure the property changes are persisted down to the database.


Re: I got the same problem that could not save the property permanently commented on Friday, 16-Nov-2007
That last comment was from Bo, the original author. That is the piece of the puzzle that some of you may be missing. The Save link button in our custom editable properties panel has the following code in its click event handler. This panel (and code) is all part of our BaseWebPart which inherits from WebPart. protected void SaveLinkButton_Click(Object sender, EventArgs e) { // Let framework know changes have been made this.SetPersonalizationDirty(); // Update the properties this.ApplyChanges(); } Hopefully this helps. Kirk


siva commented on Tuesday, 11-Mar-2008
Please provide me the sample code. so that i can understand better. Because i don't know how you are hiding the property panel under normal display. In the createchildcontrols() method i am adding my own controls to the webpart.


tejas commented on Wednesday, 28-May-2008
can you please let me what to do if i want that the enum created while creating a webpart shoudl have values as the name of all lists of that site


Neerav commented on Wednesday, 18-Jun-2008
Hi, Can you please provide your sample's source code. Thanks in advance


Kirk Liemohn commented on Tuesday, 8-Jul-2008
I'm afraid that I can't give out the source code beyond what has been posted here. It has also been about a year since this has been written/coded so my memory on this is a little rusty.


warhammer gold commented on Tuesday, 14-Oct-2008
[size=4][url=http://www.vipwargold.com/][size=4][color=#0000ff]war gold[/color][/size][/url][size=4] [/size][url=http://www.vipwargold.com/][size=4][color=#0000ff]buy war gold[/color][/size][/url][size=4] [/size][url=http://www.vipwargold.com/][size=4][color=#0000ff]warhammer gold[/color][/size][/url] [url=http://www.cheaperzone.com/][size=4][color=#0000ff]warhammer gold[/color][/size][/url][size=4] [/size][url=http://www.cheaperzone.com/Buy-WOW-Gold/WOW-Gold.Html][size=4][color=#0000ff]buy warhammer gold[/color][/size][/url][size=4] [/size][url=http://www.cheaperzone.com/][size=4][color=#0000ff]war gold[/color][/size][/url][size=4] [/size] [size=4][url=http://www.vipwarhammergold.com/][size=4][color=#0000ff]warhammer gold[/color][/size][/url] [url=http://www.vipwarhammergold.com/][color=#0000ff]buy warhammer gold[/color][/url] [url=http://www.vipwarhammergold.com/][color=#0000ff]war gold[/color][/url][/size] [size=4][url=http://www.buyfastgold.com/][size=4][color=#0000ff]warhammer gold[/color][/size][/url] [url=http://www.buyfastgold.com/buy-warhammer-gold/][color=#0000ff]buy warhammer gold[/color][/url] [url=http://www.buyfastgold.com/][size=4][color=#0000ff]war gold[/color][/size][/url][/size] [size=4][url=http://warhammer-gold.rgtrcredit.com/][size=4][color=#0000ff]warhammer gold[/color][/size][/url] [url=http://warhammer-gold.rgtrcredit.com/Buy-warhammer-gold.html][color=#0000ff]buy warhammer gold[/color][/url] [url=http://warhammer-gold.rgtrcredit.com/][color=#0000ff]war gold[/color][/url][/size] [size=4][url=http://warhammer.hellgate-pd.com/][size=4][color=#0000ff]warhammer gold[/color][/size][/url] [url=http://warhammer.hellgate-pd.com/buy-warhammer-gold.html][color=#0000ff]buy warhammer gold[/color][/url] [url=http://warhammer.hellgate-pd.com/][size=4][color=#0000ff]war gold[/color][/size][/url][/size] [size=4][url=http://www.warhammer100.com/][size=4][color=#0000ff]warhammer gold[/color][/size][/url] [url=http://www.warhammer100.com/][color=#0000ff]buy warhammer gold[/color][/url] [url=http://www.warhammer100.com/][color=#0000ff]war gold[/color][/url][/size] [size=4][url=http://www.vipaocgold.com/][size=4][color=#0000ff]aoc gold[/color][/size][/url] [url=http://www.vipaocgold.com/buy-aoc-gold/][color=#0000ff]buy aoc gold[/color][/url] [url=http://www.vipaocgold.com/][color=#0000ff]age of conan gold[/color][/url][/size] [size=4][size=4][size=4][url=http://www.aocsale.com/][size=4][size=4][color=#0000ff]age of conan gold[/color][/size][/size][/url][/size] [url=http://www.aocsale.com/buy-aoc-gold/][color=#0000ff]buy age of conan gold[/color][/url] [url=http://www.aocsale.com/][color=#0000ff]aoc gold[/color][/url][/size][/size] [size=4][url=http://www.gold-warhammer.com/][size=4][color=#0000ff]warhammer gold[/color][/size][/url] [url=http://www.warhammer100.com/][color=#0000ff]warhammer online gold[/color][/url][/size] [size=4][url=http://www.bestwarhammer.com/][size=4][color=#0000ff]warhammer online gold[/color][/size][/url] [url=http://www.cheaperzone.com/][color=#0000ff]warhammer online gold[/color][/url][/size][size=4][/size] [size=4][url=http://www.bestwarhammer.com/][size=4][color=#0000ff]warhammer gold[/color][/size][/url] [url=http://www.bestwarhammer.com/][color=#0000ff]buy warhammer gold[/color][/url] [url=http://www.bestwarhammer.com/][color=#0000ff]war gold[/color][/url][/size] [url=http://www.bestwarhammer.com/][color=#0000ff][/color][/url][/size]

war gold   buy war gold    warhammer gold
warhammer gold   buy warhammer gold    war gold   
warhammer gold   buy warhammer gold    war gold
warhammer gold   buy warhammer gold    war gold
warhammer gold   buy warhammer gold    war gold
warhammer gold   buy warhammer gold    war gold
warhammer gold   buy warhammer gold    war gold
aoc gold   buy aoc gold    age of conan gold
age of conan gold   buy age of conan gold    aoc gold
warhammer gold   warhammer online gold
warhammer online gold   warhammer online gold

warhammer gold   buy warhammer gold   war gold


wow commented on Thursday, 30-Oct-2008
lc Welcome to wow gold. We are a world class wow powerleveling store online. We supply cheap wow gold to our loyal and World of Warcraft goldreliable customers. you canwow power leveling buy really cheapwow gold wow gold here. We havewow power leveling mass available stock ofwow power leveling wow gold onwow power leveling most of the servers, sowow power leveling that we can do aRolex really instant way of wow power levelingwow gold wow golddelivery. We canwow powerleveling deliver yourwow powerleveling wow gold on powerlevelingthe order powerlevelingin a short cheap wow goldwhile. We have beencheap wow gold an ebay powerpower leveling seller and paypalpower leveling confirmed seller rolex replicaof wow gold for replica rolexyears.So it ischeap wow gold securest and safestRunescape Gold to buy RuneScape Money wow gold from Watches Rolexus. Don’t be Rolex Watchesirresolute! We arewow gold hoping to servegold wow you and helpingWatch Rolex you to have a wonderfulRolex Watch wow life! We arers gold ready now, how about you?


warhammer commented on Thursday, 27-Nov-2008

cqx commented on Tuesday, 16-Dec-2008
A new perspective into all the people of wow gold series of more than a new name, World of Warcraft, we have 24 / 7 service for buy wow gold, we will let you enjoy the fun of cheap wow gold,wow power leveling,wow gold ,buy wow gold and wow power leveling.We hope you enjoy your wow gold to bring you happiness.


cuicui commented on Tuesday, 16-Dec-2008
Leaders from developing and world of warcraft gold industrial countries met in cheap wow goldWashington Saturday for dofus kamas an emergency summit on kamas dofusthe global financial crisis. Final Fantasy XI gilVOA's Barry Wood reports the ffxi gilfive-hour meeting endedbuy ffxi gil with a resolve to work together lotro gold to keep markets openlotr gold and prevent furtherflyff penya economic weakening. Outgoing buy flyff goldUS President Bush declaredflyff money the summit a success,Maple Story Mesos saying the leaders areMapleStory mesos committed to pro-growth Maple Story mesopolicies. The meeting agreedeq2 plat on an action plan toEverQuest 2 goldassure smoother functioning EverQuest 2 platof financial markets and Ugg Bootssaid developing countries Ugg Bootsshould have more say Ugg Bootsin the weighted votingRunescape Money structure of the InternationalRunescape Power leveling Monetary Fund, aRunescape Gold provider of emergency Final Fantasy XI gilloans to countries ffxi gilin need. President Bush buy ffxi gilpraised the achievements of this first ever meeting of leaders of 20 countries that account for over 75 percent of global output.


xiang commented on Tuesday, 16-Dec-2008
He had a big family to feed. wholesale replica handbagsThey found his boatreplica designer handbags adrift with its netslouis vuitton replica handbags half in and half out. designer replica handbags wholesaleHe must have gotten into coach replica handbagsa gale and was trying todesigner replica handbags save the nets and the floats.replica coach handbags" I looked at Frank andswiss replica watches saw that tears were replica jacob watchesrunning down his cheeks.replica coach wallet Frank spoke again. "Guys, gucci replica walletyou don't know what I replica louis vuitton walletwould give to have mychanel handbag replica wallet Dad give me just one replica jewelrymore kiss on the cheek....replica tiffany jewelry wholesaleto feel his rough old facereplica designer jewelryto smell the ocean on him Replica Wallet to feel his arm around my neck.Jewelry replica I wish I had been a jewelryman then. If I had been Cheap Coach Handbagsa man, I would never fashion Handbagshave told my Dad I was too old for a goodbye kiss."


dtv antenna commented on Thursday, 18-Dec-2008
I love this application. If your looking for power and plenty of features...this is it!


ame commented on Saturday, 20-Dec-2008

car wash commented on Monday, 29-Dec-2008
Name:
URL:
Email:
Comments:

CAPTCHA Image Validation