I came across a requirement where I needed a way to be able to retrieve pages that have been tagged with a particular
Managed Metadata (MMD) value.
Let's say there's a MMD
field called Category. And the users should be able to use the Taxonomy
"picker" control to select which category value they want to filter their
results by.
Let's create a WebPart to do this. Use the Web Part Tool Pane EditorPart, add it to your Web Part for filtering. The
EditorPart doesn't do the actual persisting of the data, so I need to
create public properties on the parent Web Part that store the selected value.
My web part, "MyWebPart" has the following three public properties:
int[]
CategoryWssIds
string FilterTerm
Guid CategoryTermId
The picker control
should bound to the same node that my Category site column is already bound to,
in the MMD tree.
Here's the code for the
EditorPart class:
class Editor :
EditorPart
{
private TaxonomyWebTaggingControl termPicker;
///
<summary>
/// Adds the picker control and binds it to the same term
set that the
/// Category site column is bound to.
///
</summary>
protected override void
CreateChildControls()
{
try
{
TaxonomyField category
= SPContext.Current.Site.RootWeb.Fields["Category"] as
TaxonomyField;
if (categories !=
null)
{
TaxonomyWebTaggingControl termPicker = new
TaxonomyWebTaggingControl();
termPicker.SspId.Add(categories
.SspId);
termPicker.TermSetId.Add(category.TermSetId);
termPicker.AllowFillIn
= false;
termPicker.IsMulti = false;
termPicker.Width =
170;
this.Controls.Add(termPicker);
}
}
catch
(Exception e)
{
//Display error
message
}
}
/// <summary>
/// Takes the term
that was selected by the user in the picker control, and
/// saves its
properties to the parent web part's properties.
///
</summary>
/// <returns>A flag indicating whether the changes
could be saved or not.</returns>
public override bool
ApplyChanges()
{
try
{
termPicker =
(TaxonomyWebTaggingControl)this.Controls[0];
//Evaluate if the user
has picked a term
string selectedTaxValue =
termPicker.Text;
int separatorIndex =
selectedTaxValue.IndexOf("|");
if (selectedTaxValue != string.Empty
&& separatorIndex != -1)
{
//If the user has
selected a term, save that term and its lookup list id (or ids, if there are
child terms)
//to the parent web part. (The lookup ids are the ids of
the term in the TaxonomyHiddenList in the current
//site
collection.)
TaxonomyField category =
SPContext.Current.Site.RootWeb.Fields["Category"] as
TaxonomyField;
Guid termSetId =
category.TermSetId;
TaxonomySession session = new
TaxonomySession(SPContext.Current.Site);
Guid termId = new
Guid(selectedTaxValue.Substring(separatorIndex + 1));
string
filterTerm = selectedTaxValue.Substring(0, separatorIndex);
int[]
wssIds = TaxonomyField.GetWssIdsOfTerm(SPContext.Current.Site,
session.TermStores[0].Id, termSetId, termId, true, 100);
if
(wssIds.Length > 0)
{
MyWebPart myWebPart =
this.WebPartToEdit as MyWebPart;
myWebPart.CateogryWssIds =
wssIds;
myWebPart.FilterTerm =
filterTerm;
myWebPart.CategoryTermId =
termId;
myWebPart.SaveChanges();
}
else
{
return
false;
}
}
}
catch (Exception e)
{
return false;
}
return true;
}
///
<summary>
///Retrieves the properties stored in the web part and sets
the value of the
/// metadata picker control based on them.
///
</summary>
public override void
SyncChanges()
{
EnsureChildControls();
termPicker =
(TaxonomyWebTaggingControl)this.Controls[0];
MyWebPart myWebPart =
this.WebPartToEdit as MyWebPart;
if (myWebPart.CateogryWssIds != null
&&
myWebPart.CateogryWssIds.Length != 0 &&
termPicker.Text == string.Empty)
{
termPicker.Text =
String.Format("{0}|{1}",
myWebPart.FilterTerm,
myWebPart.CategoryTermId.ToString());
}
}
}
Now that I have an EditorPart, I need to add it to MyWebPart. I can do it
like this:
public override EditorPartCollection
CreateEditorParts()
{
Editor editor = new Editor();
editor.ID =
this.ID + "_Editor";
editor.Title = "Filter Term";
List editors = new
List();
editors.Add(editor);
return new
EditorPartCollection(editors);
}
Add the following method to make sure the changes made by the
Editor part get persisted to the web part:
public void
SaveChanges()
{
this.SetPersonalizationDirty();
}
When it's time to build my CAML query string, I do it like
this:
StringBuilder values = new StringBuilder();
for (int i = 0; i
< categoryWssIds.Length; i++)
{
values.Append("<Value
type='Integer'>");
values.Append(categoryWssIds[i].ToString());
values.Append("</Value>");
}
string
query = String.Format(@"<Where>
<In>
<FieldRef
name="Category" LookupId="TRUE"/><Values>{0}</Values>
</In>
</Where>", values.ToString());
One thing to
keep in mind is that this is querying the hidden list in the current site
collection that stores all the MMD values that have been used. So, if
you haven't used a particular term yet anywhere in your site, the
GetWssIdsOfTerm method won't give you anything back.