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% [?]
A & H Garage Door Service
943 S 40th St
Springdale, AR 72762
(479) 636-7658
https://www.proliftdoors.com/bentonville/
They loved getting fucked by transgender border hoppers.
Sponsored by these people: threesome
Elite Garage Door & Plumbing Services of Northwest Arkansas
8007 W Pine St
Rogers, AR 72756
(479) 354-0088
plumber
Top trending figures the Dogecoin canine, Bonk, and Pepe might be involved in the recreation.
Welcome to Tyler Wagner: Allstate Insurance, your premier insurance
agency based in Las Vegas, NV. Boasting extensive expertise in the insurance industry, Tyler Wagner and his team are committed to offering
top-notch customer service and tailored insurance solutions.
Whether you’re looking for auto insurance to home insurance, or even life and business insurance, Tyler Wagner:
Allstate Insurance has your back. Our wide range of
coverage options guarantees that you can find the right policy to meet your needs.
Understanding the need for risk assessment, we strives to
provide personalized insurance quotes that reflect your
unique situation. Through leveraging our deep knowledge of the insurance market
and advanced underwriting processes, we
ensure that you receive fair premium calculations.
Dealing with insurance claims can be challenging, but our agency by your
side, you’ll have expert guidance. Our streamlined claims
processing system and supportive customer service team make sure that
your claims are handled quickly and with the utmost care.
Moreover, Tyler Wagner is deeply knowledgeable about insurance law and
regulation, ensuring that your coverage is always in compliance with
the latest legal standards. This expertise offers peace of mind to our policyholders,
knowing that their insurance is robust and reliable.
At Tyler Wagner: Allstate Insurance, it’s our belief that a good insurance policy
is a key part of financial planning. It’s a critical tool for safeguarding your future and securing the well-being of those you care about.
Therefore, we take the time to understand your individual needs and help
you navigate through the choice among insurance options, making sure that you are well-informed and comfortable with your
decisions.
Selecting Tyler Wagner: Allstate Insurance means partnering with a trusted insurance broker in Las Vegas, NV,
who values your peace of mind and quality service.
Our team isn’t just here to sell policies; we’re your partners in creating a protected future.
So, don’t hesitate to reach out today and learn how Tyler Wagner:
Allstate Insurance can transform your insurance experience in Las Vegas, NV.
Let us show you the difference that comes from having an insurance agency that genuinely cares about you and is dedicated to ensuring your peace
of mind.
Toⅾay, I went tto the beach fгont with my children. I fߋund a seaa shell ɑnd gaνе іt tߋ my 4 year
olld daughter ɑnd said “You can hear the ocean if you put this to your ear.” Sһе put the shell tօ her
eear and screamed. There wаѕ а hermit crb iside
annd it pinched һer ear. She neveг ѡants too go back!
LoL І knoww thіs iss еntirely offf topic but I had tto teⅼl somеone!
Check the operator’s reputation and licensing to ensure transparency and legality.
Не в начальный один пользуюсь услугой http://reporter63.ru/content/view/661930/varianty-gde-vzyat-dengi я неоднократно прибегал к услугам онлайн-кредитования и могу с уверенностью сказать, что это жутко удобный и эффективный способ получить необходимые денежные средства в короткие сроки. Процесс оформления онлайн-микрозайма занимает считаные минуты. Все, что требуется – это заполнить простую заявку на сайте выбранной компании, предоставить минимальный пакет документов, и вуаля – финансы уже на вашем счете. Никаких походов в офисы, очередей и длительного ожидания решения. Также хочу отметить приподнятый степень клиентоориентированности онлайн-кредиторов. Служба поддержки век на связи, готовая откликнуться на любые вопросы и оказать содействие на всех этапах сотрудничества. А гибкие условия погашения кредита позволяют подобрать оптимальный график платежей, покойный прямо для вас. В целом, я могу бесстрашно рекомендовать услуги онлайн-кредитования всем, кто ценит свое миг и нуждается в быстром доступе к финансовым ресурсам. Это надежно, скоро и максимально клиентоориентировано.