Archive for July, 2008


This is a topic that comes up often when I’m doing web site design and I figured I’d throw it up here for my own reference. The challenge is to design a footer that will float to the bottom of the page regardless of the size of the content above it. Ryan’s excellent article on sticky footer’s is where I pulled 99% of this from. I made some minor tweaks to the CSS to suit my own needs but other than that, it’s not much different. Check out Ryan’s awesome article!

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
<html>
 
    <head>
 
        <link rel="stylesheet" href="layout.css" ... />
 
    </head>
 
    <body>
 
        <div class="wrapper">
 
            <p>Your website content here.</p>
 
            <div class="push"></div>
 
        </div>
 
        <div class="footer">
 
            <p>Copyright (c) 2008</p>
 
        </div>
 
    </body>
 
</html>
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
<p>* {
margin: 0;
}
</p>
 
html, body 
{
height: 100%;
}
 
.wrapper {
min-height: 100%;
height: auto !important;
height: 100%;
margin: 0 auto -2em;
padding-left:2px;
padding-right:2px;
}
 
.footer {
height: 2em;
}
 
.footer p 
{
font-family:Verdana;
font-size:9pt;
color:#696969;
font-weight:bold;
padding-top:10px;
padding-left:2px;
text-align:center;
}
 
.push 
{
height: 2em;
}

The PeopleEditor control is a common control that you’ll find implemented throughout SharePoint. If you’re building any custom web parts or application pages, you may want users to enter people specific information. The PeopleEditor is a good choice, however, there isn’t much out there in terms of documenting it’s use. Hopefully the information below will help get you started. If you are having issues, or if there is something I’ve missed in my post, please feel free to leave me a comment.

NOTE: One thing I found was that in order for this control to successfully save a user, that user has to exist within the site collection. If they don’t exist, the web.SiteUsers call will fail with an exception ‘user cannot be found’.

UPDATE: You can use the EnsureUser method to verify that the specified user exists and is a valid user of the web site. The neat thing about this method is that it will add the user to the site if they do not already exist, thus making the SiteUsers call unnecessary. Keep in mind that if you do use this method, you may need to elevate permissions to make that call, as not all users have access to add other users to your site collection.

To get started, create a new Custom List named Demo. Within List Settings, create a column of type Person or Group named Managers.

In this particular example, I’ll be building a custom application page with a single PeopleEditor control and a submit button. Create a new page (or download the files I’ve prepared for this article here), called Demo.aspx and store it in the _layouts directory.

Since the people editor control is located within the Microsoft.SharePoint.WebControls namespace, you’ll have to register the tag prefix at the top of your page:

1
<%@ Register TagPrefix="wssawc" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

Insert the control on the page. If you look at my Demo.aspx page, I’ve put my control within a table tag, but you can format this however you’d like:

1
<wssawc:PeopleEditor AllowEmpty="false" Width="300px" id="peManagers" runat="server" SelectionSet="User" />

AllowEmtpy – let’s you specify if blank values are permitted for this control
SelectionSet – can be User or SecGroup or SPGroup or all three: User, SecGroup, SPGroup
MultiSelect – set to true or false, false if you don’t want the user to be able to select more than one

Insert an asp:Button control onto the page; we’ll use this to submit the people data to the list.

1
<asp:Button ID="btnSubmit" runat="server" OnClick="btnSubmit_Click" ValidationGroup="Main" Text="OK" CssClass="ms-ButtonHeightWidth" />

In order to save values from the control to the column we created, you’ll need the following code in the button submit event:

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
protected void btnSubmit_Click(object sender, EventArgs e)
{
    // create a web object with context for the current site
 
    SPWeb web = SPContext.Current.Web;
 
    // get the entries that were entered into the people editor and store them in a string
 
    string managers = peManagers.CommaSeparatedAccounts;
 
    // commaseparatedaccounts returns entries that are comma separated. we want to split those up
 
    char[] splitter = { ',' };
 
    string[] splitPPData = managers.Split(splitter);
 
    // this collection will store the user values from the people editor which we'll eventually use
    // to populate the field in the list
 
    SPFieldUserValueCollection values = new SPFieldUserValueCollection();
 
    // for each item in our array, create a new sp user object given the loginname and add to our collection
 
    for (int i = 0; i < splitPPData.Length; i++)
    {
        string loginName = splitPPData[i];
 
        if (!string.IsNullOrEmpty(loginName))
        {
            SPUser user = web.SiteUsers[loginName];
 
            // you could also use SPUser user = web.EnsureUser(loginName);
 
            SPFieldUserValue fuv = new SPFieldUserValue(web, user.ID, user.LoginName);
 
            values.Add(fuv);
        }
 
    }
 
    // set the Person or Group column
 
    SPListItemCollection listItems = web.Lists["Demo"].Items;
 
    SPListItem manager = listItems.Add();
 
    manager["Managers"] = values;
 
    manager.Update();
}

That should do it. You should be able to save the entries to the list. If you’d like to learn how to read values from a list column into a PeopleEditor control, you can read that post here. Any feedback?

Let’s say you have an employee table and you want to be able to create a hyperlink on the employee name column with a custom url in the form of: “employee.aspx?ID=”

Within an asp.net datagrid, you could achieve this by creating a hyperlinkcolumn and specifying the DataNavigateUrlField and the DataNavigateUrlFormatString as follows:

1
<asp:HyperLinkColumn DataNavigateUrlField="EmployeeID" DataNavigateUrlFormatString="employee.aspx?ID={0}" DataTextField="Name"></asp:HyperLinkColumn>

If you’re using a Telerik TreeView control, however, the syntax is slightly different. While you can specify DataBindings within a Telerik TreeView control, there doesn’t seem to be a NavigateUrlFormatString property available. You can set the NavigateUrl and the NavigateUrlField property, but that’s not enough to get the same results as above.

The best way to accomplish this is:

Within the RadTreeView control, add an OnNodeBound event as follows. This will enable us to set our NavigateUrl at the same time our nodes are being bound to the treeview thus giving us more control:

1
<radT:RadTreeView ID="rtvEmployees" Skin="Default" runat="server" OnNodeBound="Node_Bound"></radT:RadTreeView>

Within your code behind file, create a function as follows:

1
2
3
4
protected void Node_Bound(object sender, Telerik.WebControls.RadTreeNodeEventArgs e)
{
    e.NodeBound.NavigateUrl = "employee.aspx?ID=" + e.NodeBound.Value;
}

Don’t forget that whether you build the structure programmatically or inline, you’ll need to specify the DataFieldID, the DataFieldParentID, the DataTextField and the DataValueField. In my case, I did it programmatically as follows:

1
2
3
4
5
6
7
8
9
10
11
rtvUserGroups.DataSource = dsTreeView;
 
rtvUserGroups.DataFieldID = "EmployeeID";
 
rtvUserGroups.DataFieldParentID = "ParentID";
 
rtvUserGroups.DataValueField = "EmployeeID";
 
rtvUserGroups.DataTextField = "Name";
 
rtvUserGroups.DataBind();

This post was really planned as a Part 2 to the first post I made about saving data from the PeopleEditor control. My aim for this entry is to tackle the reverse scenario: reading data from a field of type Person or Group and loading it into a PeopleEditor control. If you have any troubles with Part 1 or Part 2 of this series or if there’s something I’ve missed, I would love to hear about it. Leave a comment or drop me an email. Thanks!

If you’ve followed Part 1 of this series, you should already have a list named Demo created with a column of type Person or Group named Managers. If not, begin by creating a new Custom List named Demo. Within List Settings, create a column of type Person or Group and name it Managers. Set the Allow multiple selections checkbox to Yes.

Once you’ve created the list and the column, add a few new entries so we have some data to load.

Now let’s create a custom application page with a single PeopleEditor control on it. Create a new page (or download it here) called Load.aspx and store it in the layouts directory.

Since the people editor control is located within the Microsoft.SharePoint.WebControls namespace, you’ll have to register the tag prefix at the top of your page:

1
<%@ Register TagPrefix="wssawc" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

Insert the control on the page. This is the control we’ll be loading the data into:

1
<wssawc:PeopleEditor AllowEmpty="false" Width="300px" id="Managers" runat="server" SelectionSet="User" />

The next step will require that we wire up our Page_Load event to load the necessary data from the list to the control.

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
protected void Page_Load(object sender, EventArgs e)
{
 
    try
    {
 
        SPWeb web = SPContext.Current.Web;
 
        // get a handle to the list we’ll be pulling values from
        SPList list = web.Lists["Demo"];
 
        // using the querystring parameter containing the id, get the list item we’ll be dealing with
        SPListItem listItem = list.GetItemById(Convert.ToInt32(Request["id"]));
 
        // the managers column is of type Person or Group, so we can use a spfielduservaluecollection to     store the values from it
        SPFieldUserValueCollection users = (SPFieldUserValueCollection)listItem["Managers"];
 
        // our array will hold the entities we’ll use to eventually assign to the people editor control
        ArrayList entityArrayList = new ArrayList();
 
        // loop through each use in the collection, set the key, add to the array
        for (int i = 0; i < users.Count; i++)
        {
 
            PickerEntity entity = new PickerEntity();
            entity.Key = users[i].User.LoginName;
            entityArrayList.Add(entity);
 
        }
 
        Managers.UpdateEntities(entityArrayList);
 
    }
 
    catch (Exception ex)
    {
 
        Response.Write(ex.ToString());
 
    }
 
}

Now when you navigate to your page, pass the id of a valid item in the list, and the entries in the manager column should load: http://servername/_layouts/Load.aspx?id=1 (replace servername with the name of your MOSS install)

ASP.NET Validators Do Not Fire in Firefox

I recently had to make some upgrades to an application that was built using the .NET 1.1 framework. Just to add a bit of background to this post, I am currently using Visual Studio 2008 on my laptop and was able to successfully perform a migration of the solution from .NET 1.1 to 2.0.

When I attempted to test my ASP.NET validators, I realized that they were not working properly in Firefox. By properply, I mean, they weren’t firing at all. I did a bit of research and found that back in the .NET 1.1 days, the javascript that the validators outputted used a proprietary document.all() syntax which was not understood by non-IE browsers. The supported syntax is document.getElementByID().

In .NET 2.0, this was apparently fixed. However, even though I had converted my project successfully, I still couldn’t get the validators to fire. I did a small test where I created a new .NET 2.0 application, added some validators, and ran the application in Firefox and I found that the validators did work. So it had to be a setting in my project that was not modified during conversion.

Turns out, within my web.config, I had to change the following line of code from:

1
<xhtmlConformance mode="Legacy"/></system.web>

to

1
<xhtmlConformance mode="Transitional"/></system.web>

That resolved my issue.

So…(assuming you are using the dropdown to filter a view of some list based on the Title field)

  1. Within your site, create a new page using any standard page layout
  2. Open your site in SharePoint Designer
  3. Detach the page you created in step 1 from the page layout by right clicking on the page and selecting Detach from Page Layout
  4. Within the Task Panes, select Data Source Library
  5. Click the list you want to use as the source of the dropdown and select Insert Data Source Control
  6. With the Task Panes menu select Toolbox and insert a standard asp.net dropdownlist control
  7. Click the OOUI and select Choose Data Source
  8. Select the SPListDataSourceControl and click OK
  9. Check the box to enable autopostback
  10. Insert the list you want to filter the data on and set the following filter:

Title == [Create new Parameter]
Param name: Param1
Source: Control
ControlID: dropdownlist1
Default: foo

Save the page. When you change the dropdownlist value, it should show the selected value.

The steps below outline how to get started using Telerik Ajax within a SharePoint custom application page. If you’re developing a web part or even just a custom asp.net application, the concepts are still the same.

  1. Add the RadAjax.Net2.dll file into the GAC. If you need to find the RadAjax.Net2.dll file, if you’ve installed the Telerik web controls to your computer, they should be in the Telerik folder where you installed the Telerik suite.
  2. Insert the following register tag at the top of the aspx page:
    1
    
    <%@ Register Assembly="RadAjax.Net2, Version=1.8.1.0, Culture=neutral, PublicKeyToken=3f7b438d1c762d0b" Namespace="Telerik.WebControls" TagPrefix="radA" %>

    In order to determine what the version and publickeytoken should be, put the dll into the GAC (c:\windows\assembly) and then right click the dll, click on Properties and you can copy and paste the version and publickeytoken.

  3. IISRESET
  4. Now that you have the control registered, it’s time to use it. Within the telerik ajax dll there’s two main controls to be aware of. The ajaxpanel and the ajaxmanager. The example I’ll show below is specific to the ajaxpanel. The following info is directly from the telerik ajax help:

    When to use RadAjaxPanel

    RadAjaxPanel is a lightweight control that lets you update a part of your web page with AJAX while keeping the rest of the page working with postbacks.

    AJAX Panel is more suitable for cases when you need to update a group of neighboring controls at once. You have to wrap the controls that should be ajaxified in the AJAX Panel. Only controls that are inside the Panel will be updated via AJAX. You cannot set the Panel to update external controls on the page.

    When a control (inside the Panel) tries to postback, it will make an AJAX request and all controls in the Panel will be updated.

    When to use RadAjaxManager

    AJAX Manager offers a complete solution for turning a postback-based application into an AJAX-driven one.

    RadAjaxManager control is mostly dedicated to complex scenarios. With AJAX Manager you have many AJAX initiator controls that update different non-adjacent controls. This is the major difference with AJAX Panel, which updates only itself (and controls that it holds).

So if you have a button, that does a lookup and populates some fields as an example, all you need to do is wrap that button and those fields inside a panel control. Note that if you just wrap the button within the panel, then the fields are not affected, and so clicking on the button will result in nothing.

Give that a shot, it’s pretty straight forward and easy to do and makes your custom web applications look a whole lot slicker!

Powered by WordPress | Theme: Motion by 85ideas.