SharePoint 2010 – Ajax Panel in Web Part’s Editor Part
Have you ever wanted to have conditional property setting possibilities in your custom web parts? I have. The scenario has been that I would have wanted to render a control to web part property setting based on some other property selection – i.e. if user selects something from web part’s properties, something else would emerge to be selected from or filled in. When developing over SharePoint 2007 I had an idea how to do it with Ajax but never had the time to make it happen as in SharePoint 2007 you wouldn’t have ASP.NET 3.5 and Ajax web server extensions available in your web application by default.
In SharePoint 2010 you don’t have that limitation any more so I gave my thought a go and below is a sample what I came up with – a web part with one drop down list, two multi selectable list boxes and one text field in the web part’s editor part. Web template is chosen from the drop down list. The first list box makes all site collection’s root webs of a web application available to be selected from and the other makes a list of sites published with a selected web template. The text box contains an integer value.
Firstly, here’s the web part’s property definitions and editor part definition:
public class DemoWebPart : WebPart
{
[WebBrowsable(false), Personalizable(PersonalizationScope.Shared)]
public List<string> RootWebs { get; set; }
[WebBrowsable(false), Personalizable(PersonalizationScope.Shared)]
public List<string> Webs { get; set; }
private string _webTemplate = "BLOG#0";
[WebBrowsable(false), Personalizable(PersonalizationScope.Shared)]
public string WebTemplate
{
get { return _webTemplate; }
set { _webTemplate = value; }
}
private int _limit = 5;
[WebBrowsable(false), Personalizable(PersonalizationScope.Shared)]
public int Limit { get { return _limit; } set { _limit = value; } }
public override EditorPartCollection CreateEditorParts()
{
var editor = new DemoEditorpart
{
ID = ID + "_Editor",
Title = "Demo Editor Part"
};
return new EditorPartCollection(new EditorPart[] { editor });
}
}
Secondly, here’s the Editor Part implementation:
{
// list box to select site collection's root webs from
protected ListBox Sites;
// list box to select webs from
protected ListBox Webs;
protected DropDownList WebTemplates;
protected TextBox Limit;
protected override void CreateChildControls()
{
Limit = new TextBox { CssClass = "UserInput", Width = 20 };
// autopostback
WebTemplates = new DropDownList
{
CssClass = "UserInput",
Width = 176,
ID = ID + "WebTemplates",
AutoPostBack = true
};
Sites = new ListBox
{
CssClass = "UserInput",
Width = 176,
ID = ID + "Sites",
SelectionMode = ListSelectionMode.Multiple,
AutoPostBack = true
};
Webs = new ListBox
{
CssClass = "UserInput",
Width = 176,
ID = ID + "Webs",
SelectionMode = ListSelectionMode.Multiple
};
var webTemplates = SPContext.Current.Site.GetWebTemplates(1033);
WebTemplates.DataSource = webTemplates;
WebTemplates.DataTextField = "Title";
WebTemplates.DataValueField = "Name";
WebTemplates.DataBind();
WebTemplates.SelectedIndexChanged += WebTemplates_SelectedIndexChanged;
// get web applications site collection root webs to display
var sites = GetRootWebs();
if (sites != null)
{
Sites.DataSource = sites;
Sites.DataTextField = "Title";
Sites.DataValueField = "Url";
Sites.Rows = sites.Count + 2;
Sites.DataBind();
Sites.SelectedIndexChanged += Sites_SelectedIndexChanged;
}
var panel = new UpdatePanel { ID = ID + "UpdatePanel" };
panel.ContentTemplateContainer.Controls.Add(
new LiteralControl(@"<table cellspacing=""0"" border=""0""
style=""border-width:0px;width:100%;
border-collapse:collapse;""><tr><td>
<div class=""UserSectionHead"">"));
panel.ContentTemplateContainer.Controls.Add(
new LiteralControl(@"Site Template:<br/>"));
panel.ContentTemplateContainer.Controls.Add(WebTemplates);
panel.ContentTemplateContainer.Controls.Add(
new LiteralControl(@"</div></td></tr>
<tr><td>
<div style=""width:100%"" class=""UserDottedLine"">
</div></td></tr><tr><td>
<div class=""UserSectionHead"">"));
panel.ContentTemplateContainer.Controls.Add(
new LiteralControl(@"Site Collections:<br/>"));
panel.ContentTemplateContainer.Controls.Add(Sites);
panel.ContentTemplateContainer.Controls.Add(
new LiteralControl(@"</div></td></tr>
<tr><td>
<div style=""width:100%"" class=""UserDottedLine"">
</div></td></tr><tr><td>
<div class=""UserSectionHead"">"));
panel.ContentTemplateContainer.Controls.Add(
new LiteralControl("Sites:<br/>"));
panel.ContentTemplateContainer.Controls.Add(Webs);
panel.ContentTemplateContainer.Controls.Add(new LiteralControl(@"<tr><td><div
class=""UserSectionHead"">Limit:<br/>"));
panel.ContentTemplateContainer.Controls.Add(Limit);
panel.ContentTemplateContainer.Controls.Add(
new LiteralControl(@"</div></td></tr><tr><td>
<div style=""width:100%"" class=""UserDottedLine""></div>
</td></tr></table>"));
Controls.Add(panel);
base.CreateChildControls();
}
/// <summary>
/// event handler to list webs under the selected site collection
/// with the selected web template
/// event handler is the same as below - could use the same
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void WebTemplates_SelectedIndexChanged(object sender, EventArgs e)
{
FillWebs(Sites.Items, Webs.Items);
Webs.Rows = Webs.Items.Count + 2;
}
/// <summary>
/// event handler to list webs under the selected site collection
/// with the selected web template
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void Sites_SelectedIndexChanged(object sender, EventArgs e)
{
FillWebs(Sites.Items, Webs.Items);
Webs.Rows = Webs.Items.Count + 2;
}
/// <summary>
/// fill the Webs list box according to the selected site collection
/// </summary>
/// <param name="sites">site collections</param>
/// <param name="webs">webs</param>
private void FillWebs(ListItemCollection sites,
ListItemCollection webs)
{
webs.Clear();
foreach (ListItem item in sites)
{
var newsWebs = GetWebs(item.Value);
foreach (var web in newsWebs)
{
var listItem = new
ListItem(web.Title,
item.Value + ";" + web.ServerRelativeUrl);
if (item.Selected && !webs.Contains(listItem))
{
webs.Add(listItem);
}
else if (!item.Selected && webs.Contains(listItem))
{
webs.Remove(listItem);
}
}
}
}
/// <summary>
/// apply changes to web part
/// </summary>
/// <returns></returns>
public override bool ApplyChanges()
{
var part = (DemoWebPart)WebPartToEdit;
// apply values back to web part from editor part
int result;
if (int.TryParse(Limit.Text, out result))
{
part.Limit = result;
}
part.WebTemplate = WebTemplates.SelectedValue;
part.RootWebs = ApplyRootWebs(Sites.Items);
part.Webs = ApplyWebs(Webs.Items);
return true;
}
/// <summary>
/// sync changes from web part
/// </summary>
public override void SyncChanges()
{
EnsureChildControls();
var part = (DemoWebPart)WebPartToEdit;
// sync values from web part to editor part
Limit.Text = part.Limit.ToString();
WebTemplates.SelectedValue = part.WebTemplate;
SyncRootWebs(Sites.Items, part.RootWebs);
SyncWebs(Sites.Items, Webs.Items, part.Webs);
Webs.Rows = Webs.Items.Count + 2;
}
/// <summary>
/// apply selected site collections to web part
/// </summary>
/// <param name="listItems">Sites items</param>
/// <returns>list of selected site collections</returns>
private static List<string> ApplyRootWebs(IEnumerable listItems)
{
return (from ListItem listItem in listItems
where listItem.Selected
select string.Format("{0};{1};{2}", listItem.Text,
listItem.Value, string.Empty)).ToList();
}
/// <summary>
/// apply selected webs to web part
/// </summary>
/// <param name="listItems">Webs items</param>
/// <returns>list of seleted webs</returns>
private static List<string> ApplyWebs(IEnumerable listItems)
{
return (from ListItem listItem in listItems
where listItem.Selected
select string.Format("{0};{1};{2}", listItem.Text,
listItem.Value.Split(';')[0],
listItem.Value.Split(';')[1])).ToList();
}
/// <summary>
/// sync site collections from web part
/// </summary>
/// <param name="rootWebItems">Sites items</param>
/// <param name="rootWebs">selecetd site collections from web part</param>
private static void SyncRootWebs(ListItemCollection rootWebItems,
IEnumerable<string> rootWebs)
{
if (rootWebs == null) return;
foreach (var siteInfo in rootWebs.Select(rootWeb =>
rootWeb.Split(';')))
{
var rootWebItem = rootWebItems.FindByValue(siteInfo[1]);
if (rootWebItem != null) rootWebItem.Selected = true;
}
}
/// <summary>
/// sync webs from web part
/// </summary>
/// <param name="rootWebItems">Sites items</param>
/// <param name="webItems">Webs items</param>
/// <param name="webs">selected webs from web part</param>
private void SyncWebs(ListItemCollection rootWebItems,
ListItemCollection webItems,
IEnumerable<string> webs)
{
if (webs == null) return;
FillWebs(rootWebItems, webItems);
foreach (var siteInfo in webs.Select(web => web.Split(';')))
{
var webItemValue = string.Format("{0};{1}", siteInfo[1],
siteInfo[2]);
var webItem = webItems.FindByValue(webItemValue);
if (webItem != null) webItem.Selected = true;
}
}
/// <summary>
/// get every root web from web application - display also the
/// names of those site collections user has no right to
/// </summary>
/// <returns>list of webs</returns>
private List<SPWeb> GetRootWebs()
{
var webs = new List<SPWeb>();
SPSecurity.RunWithElevatedPrivileges(delegate
{
foreach (SPSite site in
SPContext.Current.Site.WebApplication.Sites)
{
webs.Add(site.RootWeb);
}
});
return webs;
}
/// <summary>
/// get sub webs published with a certain template
/// </summary>
/// <param name="siteName">site name</param>
/// <returns>list of webs</returns>
private IEnumerable<SPWeb> GetWebs(string siteName)
{
SPSite site = null;
SPSecurity.RunWithElevatedPrivileges(delegate
{
site = SPContext.Current.Site.WebApplication.Sites[siteName];
});
return GetWebs(site ?? SPContext.Current.Site);
}
/// <summary>
/// get sub webs published with a certain template
/// </summary>
/// <param name="site">site</param>
/// <returns>list of webs</returns>
private IEnumerable<SPWeb> GetWebs(SPSite site)
{
var webTemplate = WebTemplates.SelectedValue;
// SPWeb doesn't contain the same info as SPWebTemplate.Name
// SPWebTemplate.Name contains "TEMPLATE#N"
// where SPWeb WebTemplate contains only the "TEMPLATE"
return site.RootWeb.GetSubwebsForCurrentUser().Where(w =>
webTemplate.StartsWith(w.WebTemplate)).ToList();
}
}
The result is that we can select site collections from web part properties and the underlying webs selection is filled dynamically causing post back within the Ajax panel in the editor part. Also the web template -selection causes a post back to refresh the Webs list box to match webs found created with the selected web template. The tricky part here was to get the editor part sync properties from the web part and apply changes back to the web part and to handle the post backs caused in the panel. Below are two clips of how the property setting works:
Web Template is available to be selected from.
Sites under the selected site collections published with the selected web template are available to be selected from.
Other sites created with the selected web template are also available to be selected from.
Popularity: 4% [?]
[...] SharePoint 2010 – Ajax Panel in Web Part’s Editor Part (SharePoint Blues)Have you ever wanted to have conditional property setting possibilities in your custom web parts? I have. The scenario has been that I would have wanted to render a control to web part property setting based on some other property selection – i.e. if user selects something from web part’s properties, something else would emerge to be selected from or filled in. When developing over SharePoint 2007 I had an idea how to do it with Ajax but never had the time to make it happen as in SharePoint 2007 you wouldn’t have ASP.NET 3.5 and Ajax web server extensions available in your web application by default. [...]
[...] SharePoint 2010 – Ajax Panel in Web Part’s Editor Part (SharePoint Blues)Have you ever wanted to have conditional property setting possibilities in your custom web parts? I have. The scenario has been that I would have wanted to render a control to web part property setting based on some other property selection – i.e. if user selects something from web part’s properties, something else would emerge to be selected from or filled in. When developing over SharePoint 2007 I had an idea how to do it with Ajax but never had the time to make it happen as in SharePoint 2007 you wouldn’t have ASP.NET 3.5 and Ajax web server extensions available in your web application by default. [...]
Excellent work, well done fella!
[...] the current site collection when running code in SharePoint. I’ve also written about using Ajax panel in web parts editor part (this post is slightly edited to serve this one). I’m going to take these two posts as basis [...]
thanks i am working on something similar with two dropdownlist, where can i find to download the project for the above one?
thanks.
i started copying and pasting the code and run it and i able to see the custom editor part but when i change the Site Template the Site Collections listbox is not changing it just showing the 4 options i get and regardless what i select from the Site Template i still those 4 options…. looks like the AutoPost is not firing?
Hi Abu, I can’t tell what could be wrong in your solution but if you try and debug it you might find the problem and see if the autopostback is firing. The screenshots above are created with the provided code samples and there you can see the autopostback working (the Site Collections and Sites ListBoxes are updated). But it has been a year and a half and I remember editing the post after first publishing it, so if you find something wrong with it, let me know.
Do you have any suggestion for maintaining some sort of state in the EditorPart? For example, I am adding a LiteralControl and setting it’s text to some HTML markup. The markup is styled so that the jQueryUI Sortable plugin will run on it. I want to capture the new markup after hitting OK/Apply, but trying to get the Text property of the LiteralControl triggers CreateChildControls to run again which sets it to its old value.
Thanks!
I feel that is one of the such a lot important info for me. And i’m happy studying your article. But want to statement on some general things, The website taste is ideal, the articles is in reality excellent : D. Good process, cheers
It’s going to be finish of mine day, except before finish I am reading this
enormous article to improve my knowledge.
An impressive share! I have just forwarded this onto a colleague who has been conducting a little research on this.
And he in fact bought me lunch due to the fact
that I stumbled upon it for him… lol. So allow me to reword
this…. Thank YOU for the meal!! But yeah, thanks for spending the time to discuss this topic here on your blog.
Thanks for sharing. This gave me a very good impression!
There are three paid plans designed for individuals,
small businesses, and businesses.
I dugg some of you post as I cogitated they
were handy extremely helpful.
Rattling instructive and excellent structure of written content, now that’s user pleasant (:
.
YouTube and WhatsApp follow this with over 2 billion, then Messenger, WeChat, and Instagram,
all having 1 billion or more customers.
Excellent site. Lots of useful information here. I am sending it to several friends ans additionally sharing in delicious.
And of course, thanks to your sweat!
Awesome! Its in fact awesome paragraph, I have got much clear idea about from this article.
This website was… how do I say it? Relevant!! Finally I
have found something which helped me. Appreciate it!
I like looking through an article that can make people think.
Also, thank you for allowing me to comment.
There is certainly a great deal to know about this issue.
I love all the points you have made.
Good blog you have here.. It’s difficult to finnd excellent writing
like yours these days. I really appreciate people like you!
Take care!!
Градуировку и кондиционирование хроматографа проводят после проведения приближённо 400 анализов, при смене колонки, изменении условий.
Wohldosiert und in einer Menge, die uns keine Sorgen macht.
This is the right webpage for anyone who would like to understand this topic.
You know a whole lot its almost tough to argue with you (not that I actually will need to…HaHa).
You definitely put a fresh spin on a topic that has been written about
for many years. Excellent stuff, just wonderful!
naturally like your website however you have to test the spelling on quite a few
of your posts. A number of them are rife with spelling problems and I in finding it very troublesome to tell the truth on the other
hand I’ll definitely come back again.
We stumbled over here different website and thought I might check tings out.
I like what I see so now i’m following you. Look forward to looking over your web page again.
Really wen someone doesn’t be aware of afterward its up to other users that they will assist,
so here it occurs.
I do not know if it’s just me or if perhaps everyone else encountering problems with your
website. It seems like some of the written text in your content are running off the screen. Can someone else please provide feedback and let me know if this is happening to them too?
This might be a issue with my browser because I’ve had this happen before.
Thank you
Hello, of course this post is genuinely pleasant and I have learned lot of things from it about
blogging. thanks.
For being a giver associated with Mountainside Massage, I am
just constantly quizzed tips about how expectant persons may
help themselves to create a more beneficial maternity. I
always indicate recently available findings, which in turn indicate activity, expertise, and additionally readiness
are considered the very most important important things that individuals is capable of doing to assist them selves get a way more gratifying gestation which includes
a good birth and labor conclusion. This guidance is always
applicable to everyone, just like the suggestions to receive
%original _anchor_text% (or simply just massage
therapy).
Superbe Blog ! Ce sont de même de grandes idées. Vous avez touché quatre ou cinq monotone
sujets ici. Quoi qu’il en soit, continuez à écrire.
salut, j’ai trouvé votre blog grâce à Google en recherchant un thème
ressemblante, votre site parait génial.
Poser des questions est sérieusement chose agréable si vous ne comprenez pas quelque chose totalement, surtout ce message apporte énormément de données faciles à se rendre compte.
Bonjour cela vous dérangerait-il de partager avec quelle projet
de site vous travaillez ? Je planifie de réaliser mon propre blog dans un futur
proche mais j’ai de la peine préférer entre BlogEngine /Wordpress/B2evolution et drupal.
le fondement pour laquelle je demande est puisque votre style et style ont l’air innombrables de
la plupart des sites et je recherche quelque chose de complètement remarquable.
P. S : Mes bordée afin d’être hors sujet mais je me devais de
poser !
Après avoir lu ceci je pense que c’est réellement illuminant.
Je vous applaudis d’utiliser le temps pour mettre cet article partout sur le
web.
Nous sommes un groupe de bénévoles et commençons un nouveau
programme dans notre plate-forme. Vous avez fait
un intimidant travail et notre groupe sera à coup sur reconnaissant envers vous.
j’aurais souhaité vous remercier pour cette
grande lecture ! ! J’ai définitivement aimé chaque conception.
Nous sommes un groupe de bénévoles et commençons un nouveau programme dans notre plate-forme.
Vous avez fait un grand travail et notre groupe sera vraisemblablement appréciateur envers vous.
Merveilleux site et exceptionnel style et style !
Poser des questions est réellement chose agréable si vous ne comprenez pas quelque chose pleinement,
néanmoins ce post apporte beaucoup de données simples à admettre.
thank you pour la constitution de bonne augure.
Cependant de quelle manière pouvons-nous communiquer ?
thank you pour ce grand site d’indications. J’avais la tradition d’être à la
recherche de cette information pour ma fin.
Undeniably believe that that you said. Your favourite reason appeared to be on the web the simplest
thing to understand of. I say to you, I definitely get annoyed at the same
time as other people consider worries that they just don’t
recognize about. You managed to hit the nail upon the highest and defined out
the entire thing with no need side-effects , folks can take a signal.
Will probably be again to get more. Thanks
parfaitement inscrit rellement ! Beaucoup d’infos
ouahou ! des tonnes infos !
Je tenais à vous exprimer toute ma gratitude pour ce contenu
perspicace que vous avez partagé. Vos articles sur les IA CRM m’ont ouvert les yeux sur les avantages de l’intelligence artificielle
dans la gestion de la relation client. Grâce
à ces outils, les entreprises peuvent mieux comprendre les attentes de leurs
clients, personnaliser leur approche et renforcer leur satisfaction.
Vous avez pour le restant de nos jours fait valoir votre appréciation !
https://www.brightstonepressurewashing.com/
You actually mentioned this wonderfully!