Live Pivot from Microsoft Labs provides a great tool to show data, thus i have created a supporting ActionResult for MVC to easy the creation of the data.
This code show an example of data from a fake compaints system that uses the cusstomer ActionResult and linq to generate the data
The url that returns the CXML must have the cxml extension!!!!!! thus modify the RegisterRoutes / RegisterArea to ass a MapPath for a url ending in CXML to a controller and action (see code at end of page) <– that took a while to find out why Live Pivot would not read it!!!!
public ActionResult Index(DateTime startdate, DateTime? endDate) { ComplaintDataContext model = new ComplaintContext(); var items = model.Complaints.Where(m => m.ComplaintDate > startdate); if (endDate.HasValue) { items = items.Where(m => m.ComplaintDate < endDate.Value); } var action = new XmlLivePivotAction<Complaint>("Customer Complaints"); action.FacetCategories.Add(new FacetCategory<Complaint> { Name = "Location", Type = FacetType.String, Action = m => m.Locaion}); action.FacetCategories.Add(new FacetCategory<Complaint> { Name = "City", Type = FacetType.String, Action = m => m.City }); action.FacetCategories.Add(new FacetCategory<Complaint> { Name = "Date", Type = FacetType.DateTime, Action = m => m.ComplaintDate.ToString("s") }); action.FacetCategories.Add(new FacetCategory<Complaint> { Name = "Type", Type = FacetType.String, Action = m => m.Type }); action.ItemName = m => m.ComplaintDescription; action.Id = m => m.ComplaintId.ToString(); action.Items = items; action.Img = m => 0; action.ImageBase = Url.Content("~/content/dzc/dzc_output.xml"); return action; }
The above code is split into the following areas:
* Linq query to get the data
* Initializes a new instance of the XmlLivePivotAction class passing the Complaint as the generic type
* Set all the FacetCategories
* Set the other parameters
* return it!
The following is the source for the ActionResult and thier support classes:
/// <summary> /// Xml action /// </summary> /// <typeparam name="Model">The type of item this will use within the collection</typeparam> public class XmlLivePivotAction<Model> : ActionResult { /// <summary> /// Initializes a new instance of the XmlLivePivotAction class /// </summary> /// <param name="name">Name of the collection</param> public XmlLivePivotAction(string name) : base() { this.Name = name; this.FacetCategories = new List<FacetCategory<Model>>(); } /// <summary> /// Gets or sets the enumerable collection of items /// </summary> public IEnumerable<Model> Items { get; set; } /// <summary> /// Gets or sets the name of the collection /// </summary> public string Name { get; set; } /// <summary> /// Gets the list of categories /// </summary> public List<FacetCategory<Model>> FacetCategories { get; private set; } // FacetCategories /// <summary> /// Gets or sets the location to the DZI /// </summary> public string ImageBase { get; set; } /// <summary> /// The schema for the pivot collection /// </summary> private readonly string P = "http://schemas.microsoft.com/livelabs/pivot/collection/2009"; /// <summary> /// The override method to produce the xml output /// </summary> /// <param name="context">the context this is running in</param> public override void ExecuteResult(ControllerContext context) { context.HttpContext.Response.ContentType = "text/xml"; context.HttpContext.Response.AddHeader("content-disposition", "inline; filename=output.cxml"); using (XmlWriter writer = XmlWriter.Create(context.HttpContext.Response.Output)) { writer.WriteStartElement("Collection", "http://schemas.microsoft.com/collection/metadata/2009"); writer.WriteAttributeString("xmlns", "xsi", null, "http://www.w3.org/2001/XMLSchema-instance"); writer.WriteAttributeString("xmlns", "xsd", null, "http://www.w3.org/2001/XMLSchema"); writer.WriteAttributeString("Name", this.Name); writer.WriteAttributeString("SchemaVersion", "1"); writer.WriteAttributeString("xmlns", "P", null, this.P); this.WriteFacetCategories(writer); this.WriteItems(writer); writer.WriteEndElement(); } } /// <summary> /// Gets or sets the name function for the item(s) /// </summary> public Func<Model, string> ItemName { get; set; } /// <summary> /// Gets or sets the id function for the item(s) /// </summary> public Func<Model, string> Id { get; set; } /// <summary> /// Gets or sets the image index function for the item(s) /// </summary> public Func<Model, int> Img { get; set; } /// <summary> /// Write facet items /// </summary> /// <param name="writer">the xml writer</param> private void WriteItems(XmlWriter writer) { writer.WriteStartElement("Items"); writer.WriteAttributeString("ImgBase", this.ImageBase); foreach (Model m in this.Items) { writer.WriteStartElement("Item"); writer.WriteAttributeString("Img", string.Format("#{0}", this.Img(m))); writer.WriteAttributeString("Id", this.Id(m)); string name = this.ItemName(m); if (string.IsNullOrEmpty(name)) { name = string.Format("Fault #{0}", this.Id(m)); } writer.WriteAttributeString("Name", name); writer.WriteStartElement("Facets"); foreach (var c in this.FacetCategories) { string action = c.Action(m); if (!string.IsNullOrEmpty(action)) { writer.WriteStartElement("Facet"); writer.WriteAttributeString("Name", c.Name); writer.WriteStartElement(c.Type.ToString()); writer.WriteAttributeString("Value", c.Action(m)); writer.WriteEndElement(); writer.WriteEndElement(); } } writer.WriteEndElement(); writer.WriteEndElement(); } writer.WriteEndElement(); } /// <summary> /// Writes each of the categories /// </summary> /// <param name="writer">the xml writer</param> private void WriteFacetCategories(XmlWriter writer) { writer.WriteStartElement("FacetCategories"); foreach (var c in this.FacetCategories) { writer.WriteStartElement("FacetCategory"); writer.WriteAttributeString("Name", c.Name); writer.WriteAttributeString("Type", c.Type.ToString()); if (c.IsFilterVisible.HasValue) { writer.WriteAttributeString("IsFilterVisible", this.P, c.IsFilterVisible.Value.ToString()); } if (c.IsMetaDataVisible.HasValue) { writer.WriteAttributeString("IsMetaDataVisible", this.P, c.IsMetaDataVisible.Value.ToString()); } if (c.IsWordWheelVisible.HasValue) { writer.WriteAttributeString("IsWordWheelVisible", this.P, c.IsWordWheelVisible.Value.ToString()); } writer.WriteEndElement(); } writer.WriteEndElement(); } }
/// <summary> /// Facet category /// </summary> /// <typeparam name="Model">The type of model this category will use</typeparam> public class FacetCategory<Model> { /// <summary> /// Initializes a new instance of the FacetCategory class /// </summary> public FacetCategory() { } /// <summary> /// Gets or sets the name of the category /// </summary> public string Name { get; set; } /// <summary> /// Gets or sets the type of the category /// </summary> public FacetType Type { get; set; } /// <summary> /// Gets or sets a value indicating whether to this is a filterable category /// </summary> /// <value> /// <c>true</c> if this instance is filterable; otherwise, <c>false</c>. /// </value> /// <remarks>Leave as null to ignore this</remarks> public bool? IsFilterVisible { get; set; } /// <summary> /// Gets or sets a value indicating whether to show the metatdata /// </summary> /// <value> /// <c>true</c> if this instance is meta data visible; otherwise, <c>false</c>. /// </value> /// <remarks>Leave as null to ignore this</remarks> public bool? IsMetaDataVisible { get; set; } /// <summary> /// Gets or sets a value indicating whether to show the word wheel /// </summary> /// <value> /// <c>true</c> if this instance is word wheel; otherwise, <c>false</c>. /// </value> /// <remarks>Leave as null to ignore this</remarks> public bool? IsWordWheelVisible { get; set; } /// <summary> /// Gets or sets the name of the category /// </summary> public Func<Model, string> Action { get; set; } }
/// <summary> /// Facet type /// </summary> public enum FacetType { /// <summary> /// the facet is a string /// </summary> String, /// <summary> /// the facet is a long string /// </summary> LongString, /// <summary> /// the facet is a number /// </summary> Number, /// <summary> /// the facet is a date time /// </summary> /// <remarks> /// use <c>value.ToString("s")</c> to export as ISO /// </remarks> DateTime, /// <summary> /// The fact is a link /// </summary> Link }
the Map route example
context.MapRoute( "CXML Path for compaints", "Admin/LivePivot.cxml", new { controller = "LivePivot", action = "Index", id = "" } );
5 comments
Comments feed for this article
June 14, 2010 at 16:35
Francois Vanderseypen
Terrific, thanks for this!
Some pieces are missing in the code but it was easy to complement.
It opens a whole world of possibilities, well done.
June 18, 2010 at 14:54
Arnaud Babilone » Créer dynamiquement une collection Microsoft Live Labs Pivot avec ASP.NET MVC
[…] ré-inventer la roue, après quelques recherche sur Internet, j’ai trouvé l’excellent article MVC ActionResult to export CXML for LivePivot fournissant un très bon début de […]
October 10, 2010 at 22:48
Alexsandro
This can be useful.
Can you share this demo VS Solution code for download? Thanks
October 11, 2010 at 16:24
tepehughes
I’ll see what i can cook up for you…
May 26, 2011 at 10:57
» Silverlight 5 and PivotViewer RogerNoble.com
[…] will bring true dynamic collections without having to worry about creating custom HttpHandlers or Mvc.ActionResults to serve up […]