Well firstly - I've got to say this comes off the back of a great Sharepoint MVP and collegue of mine Ishai Sagi. Big THANKS Ishai!!!
Typically my experience with the DataFormWebPart has been through the eyes of Sharepoint Designer - open pages with webparts on them and looking at the XML configuration of these parts. It look pretty ugly AND very site/web specific - IDs all over the place etc etc.
Ishai the wealth of knowledge came up with this solution - by overriding the SetDataSourceProperties method, you can effectively create a datasource from anywhere!!!! Forgetting the IDs etc that cause all the pain.
I've marked the 2 important lines with (**) in the code.
Big Thanks Ishai!!! Folks he's always one to watch - lock his blog in and learn!! :)
Ishai mentioned that his code below is purely for educational purposes
using System;
using System.Runtime.InteropServices;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Serialization;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.WebPartPages;
using System.Data;
using System.Xml;
namespace AdvancedQueryWebPart
{
[Guid("46a8853d-415c-458e-990c-419c12fa04f5")]
public class AdvancedQueryWebPart : DataFormWebPart, IWebPart
{
public AdvancedQueryWebPart()
{
this.ExportMode = WebPartExportMode.All;
}
protected override void SetDataSourceProperties()
{
try
{
// Call a custom function that returns the data you want to show as a data table
DataTable results = GetCustomData();
if (results.Rows.Count > 0)
{
// generate xml for selected items
XmlDocument doc = new XmlDocument();
XmlNode root = doc.AppendChild(doc.CreateElement("Rows"));
foreach (DataRow row in results.Rows)
{
XmlElement rowNode = doc.CreateElement("row");
foreach (DataColumn col in row.Table.Columns)
{
string val = row[col].ToString();
XmlAttribute att = doc.CreateAttribute(col.ColumnName);
att.Value = val;
rowNode.Attributes.Append(att);
}
root.AppendChild(rowNode);
}
// create an XmlDatasource with the new data, and set it to cache for one second
XmlDataSource ds = new XmlDataSource();
ds.CacheDuration = 1;
ds.Data = doc.InnerXml;
// bind the web part to the xml
(**) this.DataSource = ds;
(**) this.DataBind(true);
}
else
{
Label noResults = new Label();
noResults.Text = "No results were found";
this.Controls.Add(noResults);
}
}
catch (Exception ex)
{
Label lblError = new Label();
lblError.Text = ex.ToString();
this.Controls.Add(lblError);
}
base.SetDataSourceProperties();
}
private DataTable GetCustomData()
{
try
{
SPWeb webSite = SPContext.Current.Web;
SPSiteDataQuery query = new SPSiteDataQuery();
//look only in document libraries
query.Lists = "<Lists ServerTemplate=\"101\" />";
//search for documents that have "Test" in the title
query.Query = @"<Where><Contains><FieldRef Name=""Title"" /><Value Type="Text"">Test</Value></Contains></Where>";
//bring back the title field of the documents
query.ViewFields = @"<FieldRef Name=""Title"" Nullable=""TRUE"" /><FieldRef Name=""FileLeafRef"" Nullable=""FALSE"" />";
DataTable items = webSite.GetSiteData(query);
return items;
}
catch (Exception ex)
{
throw new Exception("There was a problem querying the site with the query", ex);
}
}
}
}