The standard ListViewWebPart, while it does a lot of work under the hood, offers quite limited functionalities when it comes to programmatically filter the data: even if you can wire up a filter WebPart that provide multiple values, only the first one will be considered; plus you can set only a single WebPart as the ‘data provider’ for the ListView (and this makes the realization of complex filter very hard).

You can rely on different techniques to accomplish the job:

- using SharePoint designer and create custom pages there (but it’s like hard coding the things and the reusability is minimal).

- you can define a set of views and assign them to different users, but it can be easily done only in MOSS using the Target Audience feature, and you cannot do it in WSS.

- other alternatives I do not know...

I didn’t liked any of these approaches and so I decided to try to customize the ListViewWebPart. You cannot directly inherit from the control (the class itself is marked as ‘sealed’, plus it can use many external resources you never know where they can reside given the structure of SharePoint).

I started the thing trying to use the original control, but there were problems in the way it handled the views..that is to work correctly it needs to refer to an existing view in the database; but in order to apply a custom filter query to that view, you have to call for the ‘Update’ method of the view object. If the user do not have the right permission that operation will fail and you’ll have an ‘access denied, log with another user’ (or something similar) error.

To overcome this I decided to create a brand new View object based on the schema of the current view (or the view the user have selected) and to call its RenderAsHtml() method; the result is a WebPart that act as the original ListViewWebPart, but that you can easily filter and customize (even in WSS).

Here’s the code:

[Guid("b7ea3f7d-b260-4ce8-9fd0-3af5aee8e0d6")]
public class CustomListViewWebPart : System.Web.UI.WebControls.WebParts.WebPart
{
    #region Properties
 
    private string strSourceList = string.Empty;
    private string strViewOfSourceList = string.Empty;
    private string strQuery = string.Empty;
 
    /// 
    /// The List we are displaying
    /// 
    [Personalizable(true),
    WebBrowsable(),
    WebDisplayName("List Name"),
    WebDescription("Pass the name of the List to show")]
    public string SourceList
    {
        get
        {
            return strSourceList;
        }
        set
        {
            strSourceList = value;
        }
    }
 
    /// 
    /// The Default View of the list
    /// 
    [Personalizable(true),
    WebBrowsable(),
    WebDisplayName("View"),
    WebDescription("Pass the name of the View that you want to apply to the List")]
    public string ViewOfSourceList
    {
        get
        {
            return strViewOfSourceList;
        }
        set
        {
            strViewOfSourceList = value;
        }
    }
 
    /// 
    /// a CAML query to filter the object
    /// 
    /// 
    /// in a later revision we will use one or more filter providers to set this
    /// 
    [Personalizable(true),
    WebBrowsable(),
    WebDisplayName("Query"),
    WebDescription("Pass the Filter Query")]
    public string FilterQuery
    {
        get
        {
            return strQuery;
        }
        set
        {
            strQuery = value;
        }
    }
 
    #endregion
 
    public CustomListViewWebPart()
    {
        this.ExportMode = WebPartExportMode.All;
    }
 
    protected override void CreateChildControls()
    {
        base.CreateChildControls();
        
        SPWeb web = SPContext.Current.Web;
        {
            try
            {
                SPList list = web.Lists[SourceList];
 
                // create the toolbar, actually we cannot hide it, we'll need to extend the webpart and those options
                ViewToolBar toolbar = new ViewToolBar();
                SPContext context = SPContext.GetContext(this.Context, list.Views[ViewOfSourceList].ID, list.ID, SPContext.Current.Web);
                toolbar.RenderContext = context;
                Controls.Add(toolbar);
 
                // get a reference to the view we want to use
                SPView webPartView = web.Lists[SourceList].Views[ViewOfSourceList];
               
                // create a new view based on the original one and attach the filter query to it
                // in this way we do not need to modify/update the original element and
                // even a user without updating permissions can use this webpart
                XmlDocument domDoc = new XmlDocument();
                domDoc.LoadXml(webPartView.SchemaXml);
                SPView view = new SPView(list, domDoc);
                view.Query = FilterQuery;
 
                // render the view
                Literal lbl = new Literal();
                lbl.Text = view.RenderAsHtml();
                this.Controls.Add(lbl);
            }
 
            catch (Exception ex)
            {
                // todo: have a better way to report errors!
                Label lbl = new Label();
                lbl.Text = "Error occured: ";
                lbl.Text += ex.Message;
                this.Controls.Add(lbl);
            }
        }
    }
 
    protected override void Render(HtmlTextWriter writer)
    {
        EnsureChildControls();
        base.Render(writer);
    }
}

To use it, just instantiate it on a page and set the ‘List’, ‘View’ and optionally ‘Query’ properties to the right values.

On the next articles of this series I’ll show you how to create custom filters and wire them to an evolved version of this WebPart.