Udostępnij za pośrednictwem


How to implement IRuntimeFilter2 or how to target/filter web parts.

If you are looking at the various blog entries regarding IRuntimeFilter and are left wondering why it is considered a “deprecated” interface in SharePoint 2007 wonder no more! The functionality of IRuntimeFilter is not gone forever it has just been updated with newer functionality in IRuntimeFilter2. The primary functionality difference between the two interfaces is instead of implementing the filtering UI in a separate ASP.NET dialog you are now able to implement this directly in your very own web control.

This entry goes into detail on how to use this new interface. To save time I’ve borrowed the implementation of IRuntimeFilter created by Michael O’Donovan at https://blogs.msdn.com/modonovan/archive/2005/07/07/436394.aspx and updated it for IRuntimeFilter2.

The first major difference you’ll find between the two interfaces is with the InitializeStrings method. The original implementation defined the title, tooltip, button text and dialog sizing properties for a custom dialog you build and specify with the BuilderURL attribute in the <RuntimeFilter element of the web.config. (Note: The BuilderURL is no longer needed in implementations of IRuntimeFilter2)

IRuntimeFilter (Original)

public ArrayList InitializeStrings(CultureInfo cultureInfO)

{

 ArrayList strings = new ArrayList();

 strings.Add("Role Picker");

 strings.Add("Lets you pick which user roles can view this web part");

 strings.Add("Pick Role");

 strings.Add("dialogHeight:340px;dialogWidth:430px;help:no;status:no;resizable:no");

 return strings;

}

With IRuntimeFilter2 you only need to specify the title for your new web control.

IRuntimeFilter2

public ArrayList InitializeStrings(CultureInfo cultureInfO)

{

ArrayList strings = new ArrayList();

strings.Add("Choose Groups To Filter");

return strings;

}

 

 

The only new method in IRuntimeFilter2 is GetToolPaneControl(). This method is called by SharePoint to get an instance of the WebControl you are specifying for the user interface of the filter.

 

#region IRuntimeFilter2 Members

public IToolPaneControl GetToolPaneControl()

{

DevConWebControl.RFWebControl rfwc = new DevConWebControl.RFWebControl();

rfwc.ID = "ID_RDWebControl";

return rfwc;

}

#endregion

 

The implementation of RFWebControl is relatively straightforward. To keep things simple I’m only filtering on the current sites available groups but you can filter on anything.

 

    public class RFWebControl : WebControl, IToolPaneControl, INamingContainer, IPostBackDataHandler

    {

  // The listbox that holds the groups available for filtering

        ListBox lb;

       

        // Custom list entry so I know when the user wants to clear the filter

        const string CLEARVALUE = "Clear Filter";

 

        protected override void CreateChildControls()

        {

            base.CreateChildControls();

           

            lb = new ListBox();

            lb.ID = "ID_lbSelectedGroups";

            lb.SelectionMode = ListSelectionMode.Multiple;

 

            lb.Items.Add(CLEARVALUE);

            // Get the available groups available to filter on

            foreach (SPGroup spg in SPContext.Current.Web.Groups)

            {

                lb.Items.Add(spg.Name);

            }

            this.Controls.Add(lb);

 

 

            // Initialize listbox if there were groups previously selected

            if (Text.Length > 0)

            {

                String[] groups = Text.Split(new char[] { ',' });

                foreach (String g in groups)

                {

     foreach (ListItem li in lb.Items)

                    {

                        if (g.CompareTo(li.Text) == 0)

                            li.Selected = true;

                    }

                }

            }

        }

 

        protected override void OnPreRender(EventArgs e)

        {

            base.OnPreRender(e);

            // Register for postback so we can extract the selected

            // groups out in time to hand off to SharePoint

            this.Page.RegisterRequiresPostBack(this);

        }

 

        #region IToolPaneControl Members

        // This is our implementation of IToolPaneControl

        // SharePoint uses this value to persist the selected filter

        String _filterText = "";

        public string Text

        {

            get

            {

                return _filterText;

            }

            set

            {

                _filterText = value;

            }

        }

        #endregion

 

        #region IPostBackDataHandler Members

 

        bool IPostBackDataHandler.LoadPostData(string postDataKey, System.Collections.Specialized.NameValueCollection postCollection)

        {

            String controlID = "ID_lbSelectedGroups";

            String fullID = "";

 

       // Loop through the controls until we find our listbox

            foreach (String k in postCollection.Keys)

            {

                if (k.Contains(controlID))

                    fullID = k;

            }

 

            if (postCollection[fullID] != null)

            {

                // This will contain the groups selected by the user

                // So we need to set the Text property with the filter

                Text = postCollection[fullID];

 

                // If the user selected clear empty the filter

                if (Text.CompareTo(CLEARVALUE) == 0)

                    Text = "";

            }

            return true;

        }

 

        void IPostBackDataHandler.RaisePostDataChangedEvent()

        {

        }

        #endregion

  }

 

The other major difference in the IRuntimeFilter2 implementation is since I’m filtering on groups stored in comma separated values my utility function CanUserSeePart() is different.

 

 

private bool CanUserSeePart(string groups)

{

        SPUser spu = SPContext.Current.Web.CurrentUser;

 

        String [] tmpGroups = groups.Split(new char[] { ',' });

 

        foreach (String g in tmpGroups)

        {

            foreach (SPGroup spg in spu.Groups)

                if (g.CompareTo(spg.Name) == 0)

         return true;

        }

        return false;

}

 

 

To try this sample out on your own download the project from the post attachment.Once the solution is built you will need to register both DevConRuntimeFilter.dll and DevConWebControl in the global assembly cache using gacutil –i DevConRuntimeFilter.dll and gacutil -i DevConWebControl.

 

You will need to register your filter in the web.config of your SharePoint site. Keep in mind there can only be one RuntimeFilter per virtual server so if you are testing on a MOSS install you will need to comment out the original AudienceManager filter before adding this one.

 

The safest place to register your filter is immediately before the ending SharePoint element </SharePoint>.

 

 <RuntimeFilter Assembly="DevConRunTimeFilter, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b9e17e23dc48e734" Class="DevConRunTimeFilter.RuntimeFilter" />

 

Run IISReset and you should now be able to see the sample when you bring up the “Modify Shared Web Part” menu.

IRuntimeFilter2SampleCode.EXE_rename_to_exe

Comments

  • Anonymous
    February 05, 2009
    Thanks for this sample. It was a great help in implementing our WSS site. I found a small problem with the CanUserSeePart function. It works fine if you just include users within a SharePoint group but if you include AD groups it doesn't. Here is the new function I wrote to replace it.        private bool CanUserSeePart(string groups)        {            // old code to check if user was in any of the groups in string            // now using ntfs permissions on config file            string[] groupsArray = groups.Split(',');            foreach (string groupName in groupsArray)            {                try                {                    SPGroup @group = SPContext.Current.Web.Groups[groupName];                    if (@group != null)                    {                        if (@group.ContainsCurrentUser) return true;                    }                }                catch (Exception ex)                {                    // group doesn't exist - you get a nasty exception instead of the group = nothing                }            }            return false;        }

  • Anonymous
    August 10, 2009
    Thank you for this article and sample. I'm trying to realize a quite similar customizable configurable webpart. There's only question I've not found on the net with an answer: Why can I only register one runtimefilter per virtual server? Sometimes it would be helpful to add a second runtimefilter parallel to the default MOSS audience manager runtimefilter.