Custom Content Query WebPart

Introduction:-

When we create portal very often we use Content Query Web Part (CQWP) to display contents. If you are not using then start using it. Trust me its very nice.
As per me; There are 2 bad points in CQWP:-
1. We end up to modify existing style library xslt for adding xslt template. If we do so Microsoft will not support if require. Also if anything happens then entire site will crash.
2. Whatever field we wish to display; we need to add view fields detail in CQWP. For this we need to export, add fields in xml and again import webpart.

Therefore I have created a generic webpart which provide functionality to take custom xslt path and provide functionality to take viewfields. You can extend this webpart by providing other feature like query, paging etc..

Detail:-

1st we will setup site and then later we will discuss about implementation of CQWP.

Setup:-

1. Go to “Style Library”.
2. Create a new folder. In my example its “Cportal XSL Style Sheets”.

Cportal XSL Style Sheets

3. Copy all xslt from “XSL Style Sheets” to our new folder “Cportal XSL Style Sheets”.
That means we use these xslt in new custom folder; By this Custom CQWP will give OOB behavior.

xsl files

Implementation:

Now we will extent existing CQWP feature by inheriting ContentByQueryWebPart class.
There would be 2 classes.
1. CustomContentQueryWebPart: – It extent existing CQWP feature by inheriting ContentByQueryWebPart class.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
using System;
using System.Collections.Generic;
using System.Web;
using System.ComponentModel;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Publishing.WebControls;
using Microsoft.SharePoint.WebPartPages;
 
namespace Avinash
{
    ///<summary> 
    /// Extent existing CQWP feature by inheriting ContentByQueryWebPart class
    /// </summary>
    public class CustomPortalContentQuery  : ContentByQueryWebPart
    {
        [WebBrowsable(true)]
        [Category("Staging Customization")]
        [DefaultValue("")]
        [Personalizable(PersonalizationScope.Shared)]
        [WebDisplayName("List Web Relative Url")]
        [WebDescription("The url of the List or Document Library")]
        public string ListUrl { get; set; }
 
        public override ToolPart[] GetToolParts()
        {
            List toolPart = new List(base.GetToolParts());
            toolPart.Insert(0, new CustomToolPart());
            return toolPart.ToArray();
        }
 
        ///<summary> 
        /// Initialize custom xslt path and set the Changed boolean to false
        /// Note: XSLT initialization can not be dont in CreateChildControls.
        /// It has to be done in OnInit
        /// </summary>        
        protected override void OnInit(EventArgs e)
        {
            this.ItemXslLink = this.ServerRelativeItemXslLink;
            this.MainXslLink = this.ServerRelativeMainXslLink;
            // Workaround to get webpart title url in ContentQueryMail.xsl
            if (!String.IsNullOrEmpty(this.TitleUrl))
                this.FeedDescription = this.TitleUrl;
            base.OnInit(e);
        }
    }
}

2. CustomToolPart: – It Create tool part for Custom content query webpart. This will display same webpart properties like CQWP.
However it will have extra pane named as “CPortal Settings” Where we will have option set xslt file and view fields..

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
using System.Web.UI;
using System.Web.UI.WebControls;
 
namespace Avinash
{
    ///
<summary> /// Create tool part for Custom content query webpart
 /// This will display same webpart properties like CQWP.
 /// However it will have extra pane named as "CPortal Settings"
 /// Where we will have option set xslt file and view fields.
 /// </summary>
    public class CustomToolPart : Microsoft.SharePoint.WebPartPages.ToolPart
    {
        CustomPortalContentQuery webpart;
        TextBox commonViewFields;
        TextBox itemXslLink;
        TextBox conentQueryMainXslLink;
        Panel toolPanel;
        Table toolPanelTable;
 
        public CustomToolPart()
        {
            this.Title = "CPortal Settings";
        }
        protected override void CreateChildControls()
        {
            webpart = this.WebPartToEdit as CustomPortalContentQuery;
            toolPanel = new Panel();
            toolPanel.CssClass = "ms-ToolPartSpacing";
            toolPanel.Controls.Add(GetToolPanel());
            this.Controls.Add(toolPanel);
            base.CreateChildControls();
        }
 
        public override void ApplyChanges()
        {
            try
            {   // set xsl path
                webpart.ItemXslLink = itemXslLink.Text;
                webpart.MainXslLink = conentQueryMainXslLink.Text;
                webpart.CommonViewFields = commonViewFields.Text;
            }
            catch { }
            base.ApplyChanges();
        }
 
        private Control GetToolPanel()
        {
            toolPanelTable = new Table();
            toolPanelTable.CellPadding = 0;
            toolPanelTable.CellSpacing = 0;
            toolPanelTable.Style["border-collapse"] = "collapse";
            toolPanelTable.Attributes.Add("width", "100%");
            toolPanelTable.Rows.Add(GetItemXslLinkRow());
            toolPanelTable.Rows.Add(GetSeperatorRow());
            toolPanelTable.Rows.Add(GetCommonViewFieldsRow());
            toolPanelTable.Rows.Add(GetSeperatorRow());
            toolPanelTable.Rows.Add(GetContentQueryMainLinkRow());
 
            return toolPanelTable;
        }
 
        /// <summary>
        /// Create row for Item XSL
        /// </summary>
        /// <returns>row for item xsl</returns>
        private TableRow GetItemXslLinkRow()
        {
            TableRow row = new TableRow();
            TableCell cell = new TableCell();
            cell.Controls.Add(new LiteralControl
                  ("<div class="UserSectionHead"><b>Item XSL Link:</b></div>"));
            cell.Controls.Add(new LiteralControl
                  ("<div class="UserSectionBody"><div class="UserControlGroup"><nobr>"));
            itemXslLink = new TextBox();
 
            // set xsl path
            if (string.IsNullOrEmpty(webpart.ItemXslLink))
            {
                itemXslLink.Text = this.webpart.ServerRelativeItemXslLink;
            }
            else
                itemXslLink.Text = this.webpart.ItemXslLink;
 
            cell.Controls.Add(itemXslLink);
            cell.Controls.Add(new LiteralControl("</nobr></div></div>"));
            row.Cells.Add(cell);
            return row;
        }
 
        /// <summary>
        /// Create row for Common view fields
        /// </summary>
        /// <returns>row for Common view fields</returns>
        private TableRow GetCommonViewFieldsRow()
        {
            TableRow row = new TableRow();
            TableCell cell = new TableCell();
            cell.Controls.Add(new LiteralControl
                ("<div class="UserSectionHead"><b>Common View Fields:</b></div>"));
            cell.Controls.Add(new LiteralControl
                ("<div class="UserSectionBody"><div class="UserControlGroup"><nobr>"));
            commonViewFields = new TextBox();
            commonViewFields.Text = this.webpart.CommonViewFields;
            cell.Controls.Add(commonViewFields);
            cell.Controls.Add(new LiteralControl("</nobr></div></div>"));
            row.Cells.Add(cell);
            return row;
        }
 
        /// <summary>
        /// Create row for Content Query Main XSL
        /// </summary>
        /// <returns>row for Content Query Main xsl</returns>
        private TableRow GetContentQueryMainLinkRow()
        {
            TableRow row = new TableRow();
            TableCell cell = new TableCell();
            cell.Controls.Add(new LiteralControl
              ("<div class="UserSectionHead"><b>ContentQueryMain XSL Link:</b></div>"));
            cell.Controls.Add(new LiteralControl
                 ("<div class="UserSectionBody"><div class="UserControlGroup"><nobr>"));
            conentQueryMainXslLink = new TextBox();
            // set xsl path
            if (string.IsNullOrEmpty(webpart.ItemXslLink))
            {
                conentQueryMainXslLink.Text = this.webpart.ServerRelativeMainXslLink;
            }
            else
                conentQueryMainXslLink.Text = this.webpart.MainXslLink;
 
            cell.Controls.Add(conentQueryMainXslLink);
            cell.Controls.Add(new LiteralControl("</nobr></div></div>"));
            row.Cells.Add(cell);
            return row;
        }
 
        /// <summary>
        /// Create a dotted seperator row
        /// </summary>
        /// <returns>row for dotted seperator</returns>
        private TableRow GetSeperatorRow()
        {
            TableRow row = new TableRow();
            TableCell cell = new TableCell();
            cell.Controls.Add(new LiteralControl
                ("<div style='width:100%' class='UserDottedLine'></div>"));
            row.Cells.Add(cell);
            return row;
        }
    }
}

Once you deploy this web part it will display webpart property like below image:-

webpart settings

You can see that now we have custom pane property as “CPortal Settings” where we can set xsl path and view fields. In my case the path will be like below image:-

xsl path
Here viewfields you can add as per your requirement.

Hope it helps!
Thanks!
Avinash

calendarMarch 14, 2012 · cardInfoyen · comments10 Comments
tagTags: , , , , , , , , , ,  · Posted in: CQWP, MOSS, SharePoint

10 Responses

  1. Shafaqat Ali - March 30, 2012

    Thank, very helpful.

  2. Shafaqat Ali - March 30, 2012

    Thanks, very helpful.

  3. Daniel - November 27, 2012

    This is interesting. Have you tried overriding the Query property and making it personalizable. I want my users to have their own query filters whilst editing and view a page in personalization mode. Do you think this possible

  4. Infoyen - November 27, 2012

    Hi,
    You may try to use ProcessDataDelegate. See below example:-

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
    protected override void OnInit(EventArgs e)
    {
     this.ProcessDataDelegate += new ProcessData(modifyDataTable);
     base.OnInit(e);
    }
    private DataTable modifyData(DataTable dtCqwp)
    {
     DataTable dtNewData = dtCqwp;
     // dtCqwp is the final result of your content query web part.
     // Now on dtNewData datatable you can apply filter using data table .Select() expressions
     // and finally return updated "dtNewData" object
     
     // for example: I apply sort on "Company" column and return updated object
     
     DataView dvModified = dtNewData.DefaultView;   
     dvModified.Sort = "Company";     
     dtNewData = dvModified.ToTable();
     return dtNewData;
     
    }
  5. Daniel - November 27, 2012

    Hi Infoyen

    I can see what you are trying to do – ” Sort” could be a personalisable property. Unfortunately, my users want to set their own unique query ( involving CTs and site cols). I would therefore need to replicate the ToolPart query functionality with my own personalisable properties.

    Previously, I had tried ovrriding the QueryOverride property but all this does is disable the query part of the tool part settings… I understand a few people have complained to Microsoft about this.

  6. Infoyen - November 27, 2012

    Hello,

    I never did this part. But i think Microsoft expose 1 property called “QueryOverride”.
    So get value of “QueryOverride” from web part tool pane property and set into your personalisable property.

    To modify this you need to generate caml query and assign it back into “QueryOverride” property.

    Please check these url:-
    http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.publishing.webcontrols.contentbyquerywebpart.queryoverride.aspx

    Customize the Content Query Web Part by using Custom Properties

    These might help you.

  7. SivanesanB - November 12, 2013

    I got the error, Using the generic type ‘System.Collections.Generic.List’ requires 1 type arguments

  8. Infoyen - December 29, 2013

    Please provide more detail.

  9. Ravi - July 17, 2014

    Hi, As i used your code for customizing content query webpart. In properties toolpane Properties category name is showing but controls(ItemxslLink:, common view fields:, content query main xsl Link:) are not visible..

  10. Infoyen - July 17, 2014

    Normally it works for me and for my other blog users…
    Seems you are doing small mistake which you are not able to catch.

    Review your code and check simple things. may be like-
    1. Did you use => this.Controls.Add(toolPanel);
    2. Did you use =>
    public override ToolPart[] GetToolParts()
    {
    List toolPart = new List(base.GetToolParts());
    toolPart.Insert(0, new CustomToolPart());
    return toolPart.ToArray();
    }

    Rest i may not be able to guide until unless i don’t see your full code.
    Let me know if you have found the solution..

Leave a Reply

Spam Protection: , required

myworldmaps infoyen