Intro

Ok, ladies and gents, I just couldn't take it any longer! The out of the box navigation for blogs is less than ideal and although I will be soon investigating different content query web parts to accomplish the same thing, I went ahead a build a new one. Essentially, I wanted a grouping of blog articles in some sort of tree view as a web part. Simple right? The answer to this is actually yes. What I will plan to do here is simply write a quick code base and deploy to my site. At that point, I can just add my web part and ta-da, workie workie.

Implementation

  1. Create a CAML query based on the "Posts" list that just orders the posts by publish date. This will look something like:

using (SPWeb spWeb = SPContext.Current.Web)

{

string DocumentLib = "Posts";

string sUrl = spWeb.Url;

string PostDate = string.Empty;

SPList list = spWeb.Lists[DocumentLib];// here DocumentLib is name of the name of documentlibrary we are passing

SPQuery docQuery = new SPQuery();

docQuery.ViewFields = @"<FieldRef Name=""LinkTitle""/>";

docQuery.ViewFields += @"<FieldRef Name=""PublishedDate""/>";

string CamlQ =

@"<OrderBy>

<FieldRef Name=""PublishedDate"" Ascending=""False"" />

</OrderBy>";

docQuery.Query = CamlQ;

 

  1. Loop through these posts creating a string representation of XML that looks something like:

sBlogs = @"<?xml version=""1.0"" encoding=""utf-8"" ?>";

sBlogs += @"<BlogPosts>";

SPListItemCollection docList = list.GetItems(docQuery);

foreach (SPListItem item in docList)

{

DateTime PublishedDate = DateTime.Parse(item["PublishedDate"].ToString());

if (PostDate != PublishedDate.ToString("MMMM yyyy"))

{

//Make sure not first time through loop

if (PostDate != string.Empty)

{

sBlogs += @"</PostMonth>";

}

PostDate = PublishedDate.ToString("MMMM yyyy");

sBlogs += @"<PostMonth name=""" + PostDate + @""">";

}

sBlogs += @"<PostName name=""" + item["LinkTitle"].ToString() + @""" url=""" + sUrl + @"/Lists/Posts/Post.aspx?ID=" + item.ID.ToString() + @"""/>";

}

sBlogs += @"</PostMonth>";

sBlogs += @"</BlogPosts>";

}

return sBlogs;

}

 

  1. Create an XML Data Source and attach your bindings accordingly

XmlDataSource xBlogPosts = new XmlDataSource();

xBlogPosts.EnableCaching = false;

XmlDocument xXMLDoc = new XmlDocument();

TreeNodeBinding tnbTop = new TreeNodeBinding();

TreeNodeBinding tnbMonth = new TreeNodeBinding();

TreeNodeBinding tnbName = new TreeNodeBinding();

string sXMLDoc = string.Empty;

try

{

if (!Page.IsPostBack)

{

//Create XML

sXMLDoc = GetBlogPosts();

//Load XML DataSource

xXMLDoc.LoadXml(sXMLDoc);

xBlogPosts.Data = xXMLDoc.InnerXml;

 

  1. You will then set your XPath to narrow down your tree

xBlogPosts.XPath = "BlogPosts/PostMonth";

 

  1. Create a Treeview and set the XML Datasource be the binding

//Create TreeNode Bindings

tnbTop.DataMember = "BlogPosts";

tnbTop.Text = "Blog Posts";

tnbMonth.DataMember = "PostMonth";

tnbMonth.TextField = "name";

tnbName.DataMember = "PostName";

tnbName.TextField = "name";

tnbName.NavigateUrlField = "url";

//Associate TreeView Bindings

tv.DataBindings.Add(tnbTop);

tv.DataBindings.Add(tnbMonth);

tv.DataBindings.Add(tnbName);

//Bind

tv.DataBind();

tv.CollapseAll();

 

  1. Add the tree view through the RenderChildren method as explained in an earlier post here.

this.Controls.Add(tv);

 

  1. Make sure you dispose your objects that you explicitly instantiate

xBlogPosts.Dispose();

xBlogPosts = null;

xXMLDoc = null;

tnbTop = null;

tnbMonth = null;

tnbName = null;

tv.Dispose();

tv = null;

 

  1. Build and deploy your finished webpart
  2. Add the webpart to the page(s) in question

 

Finishing touches

For full sample of the code, simply email me or send comment. I have uploaded the cs file, however, anonymous access is not yet enabled. I was tired of writing the code in the blog all the time, so figured I would try a different approach this time.

The end product looks something like:

 

 image

Pretty cool huh?