Sometimes you might need a way to be able to retrieve pages that have been tagged with a particular Managed Metadata (MMD) value. In this scenario, let’s say that we have a MMD field called Category. I want to be able to let my users use the Taxonomy “picker” control to select which category value they want to filter their results by.

To do this, I creat a Web Part Tool Pane EditorPart that I add to my Web Part that does the 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

I want the picker control to be 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);
}

I need to 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.