Project Server ItemSwapper control

ItemSwapper hasn’t been documented by Microsoft so its behaviour may change between service packs – use at your own risk!

With the 2007 version, Project Server is now a SharePoint application. One of the best things about this is the nifty stuff you get out of the box as part of SP. Custom controls are a highlight, of which there are many that can be used in your custom Project Server solutions. Even better is that Project Server 2007 comes with some cool controls of its own which you can use in any solution running within Project Server. My latest discovery is the handy ItemSwapper.

ItemSwapper

ItemSwapper

This might look familiar to you from popular administration pages such as “Manage Queue” or “Manage Groups”. Just by popping one of these on your page, you get a pretty flawless interface to selecting projects. It’s also speedy and has some great features both client and server side. It’s great to use in a web part used for selecting report parameters, so that’s what we’re going to build in this post!

First of all, let’s have a look at two other custom controls used by ItemSwapper. There is the ItemSwapperLabel (extended from System.Web.UI.WebControls.Label) which renders the text above each list, and ItemSwapperSelect (extended from System.Web.UI.HtmlControls.HtmlSelect) which renders the list itself. Data binding is done with ItemSwapperSelect and the ‘parent’ ItemSwapper control renders all of these controls for you.

The ItemSwapper control refers to the two select lists as the ‘alpha’ and ‘beta’ lists (originally designed for Greek Project Server?). In our example the beta list will be blank for us to add projects into, so we only want to initalise the alpha list. Looking at the code, our CreateChildControls method contains:

protected override void CreateChildControls()
{
    alphaSelect = new ItemSwapperSelect();
    alphaSelect.Multiple = true;

    projectSwapper = new ItemSwapper();
    projectSwapper.ID = "projectSwapper";
    projectSwapper.TrackBetaListChanges = true;
    projectSwapper.AlphaSelect = alphaSelect;
    projectSwapper.LblAlphaList.Text = "Available Projects";
    projectSwapper.LblBetaList.Text = "Selected Projects";
    projectSwapper.DisplaySelectedItemText = false;
    projectSwapper.ShowBetaUpDownButtons = true;
    projectSwapper.ShowRestoreAllButton = true;
    projectSwapper.ShowRemoveAllButton = true;
    this.Controls.Add(projectSwapper);
}

This should be pretty self-explanatory (we will discuss the ID and TrackBetaListChanges properties later in this post). Now let’s perform a data bind in our OnLoad method:

protected override void OnLoad(EventArgs e)
{
    if (!Page.IsPostBack)
    {
        DataTable projects = DataLayer.GetProjects();
        projectSwapper.DataSource = projects;
        projectSwapper.DataTextField = "Name";
        projectSwapper.DataValueField = "Uid";
    }
}

This will now render fine, but the finishing touch is a workaround to what I would call a bug. If you set ShowRestoreAllButton to true, this will display the “Add All” button. However it is important to know that this button is greyed out unless the user has selected an item first, meaning that will need two clicks to add all projects to the other list. I don’t know why Microsoft would have done this, but to get around it, add the following code to our OnPreRender method:

protected override void OnPreRender(EventArgs e)
{
    alphaSelect.SelectedIndex = 0;
}

Have a look at the work so far as the ItemSwapper should now render!

Now let’s make use of the items chosen in the lists. First of all we’ll need a button in our web part for users to click on and start the report generation. We’ll also need at least one hidden field that will contain the selected items for us to use on the server side. Note that there is quite a bit of data we can get from the ItemSwapper JavaScript object, such as a count of items for both lists, text labels of chosen items for both lists, and values (e.g. project GUIDs) of chosen items for both lists!

To be able to do retrieve the data on the client side there are two key properties we need to set when creating the ItemSwapper which I touched upon earlier: ID and TrackBetaListChanges (or if you care about the alpha list, TrackAlphaListChanges). We need to use JavaScript to get a reference to the ItemSwapper object and setting ID lets us use document.getElementByID() to do this. (Surprisingly and fortunately, ID doesn’t get mangled in usual SharePoint fashion when rendered.) Setting TrackBetaListChanges sets a property on the JavaScript object to, well, track beta list changes.

So going back to CreateChildControls(), let’s add the following code and connect our server code to the client:

chosenProjectValues = new HiddenField();
this.Controls.Add(chosenProjectValues);

createButton = new Button();
createButton.Text = "Create";
createButton.Click += CreateButton_Click;  // server-side processing done in this method
createButton.OnClientClick = String.Format("SaveItemSwapperValues('{0}', '{1}');", projectSwapper.ID, chosenProjectValues.ClientID);
this.Controls.Add(createButton);

Everything’s ready now on the server side. We just need to create the SaveItemSwapperValues JavaScript function. Put this JavaScript wherever is standard for your projects.

function SaveItemSwapperValues(itemSwapperClientID, chosenValuesClientID)
{
    var chosenValuesField = document.getElementById(chosenValuesClientID);
    var itemSwapper = document.getElementById(itemSwapperClientID);
    chosenValuesField.value = itemSwapper.GetBetaListValuesAsString();
}

That’s it! Now when your server-code hits CreateButton_Click(), you should find a nice comma-separated list of project GUIDs in the Value property of your hidden field that can be used to generate reports!

But it’s nice to take things a bit further… Our Create button is always active, even when no projects are in the chosen list. Well then, behold! The ItemSwapper contains JavaScript event handling functionality! Add script that runs on startup such as this:

var itemSwapper = document.getElementById('projectSwapper'); // 'projectSwapper' should be passed as a parameter and not hard-coded
itemSwapper.OnAlphaListChange = ChosenProjectsChanged;
itemSwapper.OnBetaListChange = ChosenProjectsChanged;

Then add the following with the SaveItemSwapperValues function:

function ChosenProjectsChanged()
{
    var itemSwapper = document.getElementById('projectSwapper');
    var createButton = /* how you get this reference depends on your environment */
    if (itemSwapper.betaListItemCount == 0)
    {
        createButton.disabled = true;
    }
    else
    {
        createButton.disabled = false;
    }
}

Now we’re talkin’ – a smart ItemSwapper. And that’s not all, there is heaps of handy JavaScript goodness you can hook on to if you’re able to navigate to this file and have a look: C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS\PWA\LIBRARY\ItemSwapper.htc.

Last but not least, none of the ItemSwapper controls are sealed so you are free to extend them with your own functionality!

This entry was posted in Project Server and tagged , , . Bookmark the permalink.
  • Amir

    Great post.
    I wished i have seen that before implementing such a control myself.
    It probably would have save me a day or two.

  • Amir

    Great post.
    I wished i have seen that before implementing such a control myself.
    It probably would have save me a day or two.

  • Roy

    Hi Alex,
    Would you happen to know how to use the TreePicker control in a similar manner?

    Thanks,
    Roy

  • Anky

    Hi Alex,
    What all DLLs i need to add to my project for this control? I am getting the following error when i try to use this control in my project. Please guide me.

    Could not load file or assembly 'Microsoft.Office.Project.Server.Optimizer' or one of its dependencies. An attempt was made to load a program with an incorrect format.
    FYI- I tried by including Microsoft.Office.Project.Server.Optimizer.dll as well

blog comments powered by Disqus