Category: Development

Setting the masterpage Url

Masterpages are great. You can change the appearance from your website very easy by modifying the default.master masterpage in the root of your sitecollection. But how do you get all pages beneath to use the same masterpage? Some pages use their own masterpage library, and ignore the one from the sitecollection rootsite.

With this little tool, you can set the masterpage Url for all subwebs of a sitecollection to the masterpage Url from your rootweb, or some url you specify.

Syntax: SharePointMasterpage.exe http://sitecollectionurl [pathToAlternativeMasterpage]

You can download this little tool here.

(If you are in a MOSS environment, you can set the masterpage in the site settings, if you select to use this masterpage for all sites beneath.)

Update:

I updated my tool to set the masterpage Url. Now you can set the masterpage Url for a Web and its subwebs only.

Update April 2011:

The tool will now detect if you are running SharePoint V3 or 2010 and set the masterpage accordingly to default.master or v4.master. This detection is automatically performed, if you do not specify the second parameter.

How to use the SharePoint Web Controls

SharePoint brings its own controls, which can be used to display list items. In this article I want to show you how to use them in a Webpart. It took me a while to figure this out, because the documentation is kind of incomplete L

OK. Lets start. First lets find out which SharePoint Web Control belongs to which data type in SharePoint.

 

 

 

 

 

SharePoint Web Control

SharePoint data type

SharePoint Web Control

Single line of text

TextField

Multiple lines of text

 

PlainText

NoteField

Rich Text

RichTextField

Enhanced Rich Text

RichTextField

Choice

 

Dropdown

DropDownChoiceField

Radio Button

RadioButtonChoiceField

Number

NumberField

Currency

CurrencyField

Date and Time

DateTimeField

Lookup

 

Single Item

LookupField

Multiple Items

MultipleLookupField

Yes/No

BooleanField

Person or Group

UserField

Hyperlink or Picture

UrlField

Calculated

UrlField

Business data

 

How do we find which control belongs to the data type? We can simply look up this information on each field:

string siteUrl = "http://sharepoint";
string webUrl = "spscontrols";

using (SPSite site = new SPSite(siteUrl))

{

using (SPWeb web = site.AllWebs[webUrl])

{

SPList list = web.Lists["ControlTest"];

foreach (SPField field in list.Fields)

{

Console.WriteLine(field.Title + " – " + field.FieldRenderingControl);

}

}
}

SPControlMode

You can the controls in different Control Modes:

  • SPControlMode.Edit behaves like in an editform page of a list
  • SPControlMode.Display shows the data without the ability to change the values

Use the Controls

So how do we use these controls? The answer to this question is simple: Just use them like "normal" System.Web Controls.

RichTextField rtf = new RichTextField();
rtf.ID = "MultilineRichText";
rtf.ListId = list.ID;
rtf.ItemId = item.ID;
rtf.FieldName = "MultilineRichText";
rtf.ControlMode = SPControlMode.Edit;
this.Controls.Add(rtf);

In this case the RichTextField shows the content from the "MultilineRichText" field from our list, and our listitem in the Editmode. ID and FieldName are the Displayname from our field. You have to set the List, Item and FieldName for the Control, because usually the SharePoint Controls will use the SPContext content (remember: the controls are used in the editform, newform.. pages of every SharePoint List).

With some lines of code, you can display all fields e.g. from the DefaultView of a SharePoint List:

Table table = new Table();
TableRow row;
TableCell cell;
for (int i = 0; i < list.DefaultView.ViewFields.Count; i++)
{

string fieldName = list.DefaultView.ViewFields[i];
SPField field = list.Fields.GetField(fieldName);

row = new TableRow();
cell = new TableCell();
cell.Text = field.Title;
row.Cells.Add(cell);

cell = new TableCell();

// Add a control from RH.SharePoint.SharePointWebControls
Control cntrl = SharePointWebControls.GetSharePointControls(field, list, item, SPControlMode.Display);
// if the control is null (because it can not be rendered with a SharePoint Control) return
if (cntrl == null) continue;

cell.Controls.Add(cntrl);
row.Cells.Add(cell);

cell = new TableCell();
cell.Controls.Add(SharePointWebControls.GetSharePointControls(field, list, item, SPControlMode.Edit));
row.Controls.Add(cell);
table.Rows.Add(row);

}

this.Controls.Add(table);

Use a generic control

Instead of finding a specific control for each SPField, you can use the BaseFieldControl. The advantage is, that it doesn’t matter which field you want to render. The right control will be used.

 
I have updated my class to use the generic instead of finding the matching Webcontrol. This approach makes it easier to use MOSS controls. You don’t have to distinct between WSS and MOSS controls any more.

You can Download the RH.SharePoint.SharePointWebControls class here.

Update:

I updated my SharePointWebControls.

Update 21. Apr 2008:

I updated my SharePointWebControls. This version includes a seperate file, which handels publishing controls from the Microsoft Office SharePoint Server 2007.

Update 19. Jan 2009:

SharePoint Web Controls to access remote content

Update 22. Feb 2009:

The class not uses a generic control instead of a control for each field type.

Write a SPFieldUser

If you have a list which contains a SPFieldUser field (with multiple selection), you can add users too it with the following code:

using (SPSite site = new
SPSite("http://site"))

{

using (SPWeb web = site.AllWebs["Web"])

    {

    SPList list = web.Lists["List"];

    SPListItem item = list.Items[0];

    SPFieldUserValueCollection values = (SPFieldUserValueCollection)item["Users"];

    SPUserCollection users = web.AllUsers;

    foreach (SPUser user in users)

    {

        values.Add(new
SPFieldUserValue(web, user.ID, user.Name));

    }

    item["Users"] = values;

    item.Update();

    }

}

In this example the list "List" would contain a field with the name "Users", which takes users. All web users are added to the field "Users" of the first list item, which is then updated.

Ajax Webpart displays Webservice data

In this post I want to show how to create an Ajax Webpart, which receives its data from a Webservice – and until the data arrived – shows a status bar.

As base for the Webpart, I took the one from Mark Collins and his great article http://sharethispoint.com/archive/2006/11/15/Build-web-parts-with-ajax.aspx.

The approach is to render the Webpart with only a <DIV>, and let the client – after it finishes querying the Webservice – fill the data into the <DIV> previously created.

The original version from Mark Collins comes without server side controls. I created the <DIV> as a HTMLGenericControl, because I wanted to have more control over it (and I was curious if it worked).

The basic stays the same. Long running operations are moved from your normal Webpart to the RaiseCallbackEvent method.

public
string GetCallbackResult()

{


return
this._AjaxData;

}

 

public
void RaiseCallbackEvent(string eventArgument)

{


this._AjaxData = CalculateContent();

}

The content returned by the CalculateContent Method is a simple string, which the clients renders later into the <DIV> element.

string CalculateContent()

{


string returnString = string.Empty;

 


try

{


TextWriter tw = new
StringWriter();


HtmlTextWriter _TxtWriter = new
HtmlTextWriter(tw);

 

_Grid = new
SPGridView();

_Grid.DataSource = GetGridDataSource();

 


// catch if the grid datasource is empty


if (_DS == null)

{


return
"<IMG src=\"/_layouts/images/BROKENLINK.GIF\" border=\"0\"/> no data received";

}


_Grid.DataBind();

 

_Grid.RenderControl(_TxtWriter);

returnString = _TxtWriter.InnerWriter.ToString();

}


catch (Exception ex)

{

_ErrorText += "Error in CalculateContent:\r\n:" + ex.ToString() + "\r\n";

returnString = _ErrorText;

}

 


return returnString;

}

This approach has a big disadvantage. You cannot use sorting, paging and filtering in the SPGridView, because it is created on the client side. You can use grouping, though. So what can we do about sorting and paging?

  • Sorting can be realized with a Webpart property, which takes the sort field an order, and sorts the underlying DataSet/DataView.

private
if (!String.IsNullOrEmpty(_SortString))

{


string[] sortArray = _SortString.Split(‘;’);


if (sortArray.Length == 2)

{

SortExpression = sortArray[0];

SortDirection = sortArray[1];


if (DataSetContainsField(_DS, SortExpression))

{

_DS.Tables[0].DefaultView.Sort = SortExpression + " " + SortDirection;

}

}

}

  • Filtering is also realized with a Webpart property, and modifying the DataSet/DataView

if (!String.IsNullOrEmpty(_FilterString) && _FilterString.Contains("="))

{


string filterColumnName = _FilterString.Substring(0, _FilterString.IndexOf(‘=’));

 


// catch typos in the filter


if (DataSetContainsField(_DS, filterColumnName))

{

_DS.Tables[0].DefaultView.RowFilter = _FilterString;

}

}

  • Paging: As soon, as I find a better solution, I will tell you about it J

Download the code here.

Webpart Development

Visual Studio Extensions

If you want to write your own Webpart, you can start from scratch with a Class Library, or use the templates from http://www.microsoft.com/downloads/details.aspx?FamilyID=19f21e5e-b715-4f0c-b959-8c6dcbdc1057&DisplayLang=en

The downside of this VS templates is, that they can only be used on a computer, which has SharePoint installed, and you cannot open a project created with the VS templates with a VS on which the templates are not installed.

Server side controls

Ishai Sagi wrote a great article about Webpart development. His article is about server side controls and data binding in Webparts.

Here is the link to his great article: http://feeds.feedburner.com/~r/sharepointmvpblogs/~3/106217340/server-side-controls-and-data-binding.html

Ajax

Mike Ammerlaan shows in his article how to integrate Ajax in SharePoint, and how to create a simple Ajax Webpart.

He also explains how to use UpdatePanels with Ajax, and how to disable the default SharePoint form action.

http://feeds.feedburner.com/~r/sharepointmvpblogs/~3/106217340/server-side-controls-and-data-binding.html

Ajax #2

Quote:

In this post I’m going to explain how to start using ajax in your web parts. The goal of this article is to reproduce functionality similar to the KPI and BDC web parts in MOSS 2007. If you don’t know what ajax is or the basics of how it works this article is probably not for you.

http://sharethispoint.com/archive/2006/11/15/Build-web-parts-with-ajax.aspx

Extend the simple Webpart

Now that we know how to create a simple Webpart, we want to add more functionality to it. Let us start with some Controls.

  1. Declare a Control as class variable
  2. Create it in CreateChildControls
  3. Modify the Control in OnPreRender
  4. Render the Control with its content

Declare a Control

public
class
simpleWebpart:WebPart

{

private
HtmlGenericControl _MyDiv;

CreateChildControls

This method creates the control. After the creation, we will be able to access the control from elsewhere, to modify its properties or its content.

protected
override
void CreateChildControls()

{

base.CreateChildControls();

 

// Create a new instance, and add it to the Controls

_MyDiv = new
HtmlGenericControl("DIV");

Controls.Add(_MyDiv);

}

Modify the Control

After the control exists, we can modify it.

protected
override
void OnPreRender(EventArgs e)

{

    base.OnPreRender(e);

 

_MyDiv.Attributes.Add("style", "padding: 20px; margin: 20px; border-style: groove; background-color: #FFFFFF;");

_MyDiv.InnerHtml = "I like SharePoint";

}

Rendering

Finally we render our controls, so that we actually see what we created. If we forget to do so, the controls will be generated, but not visible.

protected
override
void Render(HtmlTextWriter writer)

{


// Determines whether the server control contains child controls.


// If it does not, it creates child controls.

EnsureChildControls();

 


// Renders the ChildControls

RenderChildren(writer);

}

Deploy and Debug a Webpart to your SharePoint Server

To deploy a Webpart to a SharePoint Installation, complete the 3 steps beneath:

  1. Copy the dll from your Webpart to the bin folder of a webapplication
  2. Register the dll in the web.config as safe
  3. Add the Webpart to the Webpartgallery of a sitecollection
  4. Debug the Webpart

Copy the dll from your Webpart to the bin folder of a webapplication

Copy your dll to the bin folder of your IIS virtual server directory. In my case this is "C:\Inetpub\wwwroot\wss\VirtualDirectories\45079\bin".

If you don’t know where this directory might be, look it up in the IIS Manager.

Register the dll in the web.config

Open the web.config (e.g. "C:\Inetpub\wwwroot\wss\VirtualDirectories\45079\web.config"). Find the <SafeControls> section, and add a line like:

<SafeControl
Assembly="simple Webpart HOWTO, Version=1.0.0.0, Culture=neutral, PublicKeyToken=2e6fe95c9937e6f4"
Namespace="simple_Webpart_HOWTO"
TypeName="*"
Safe="True" />

The Assembly Name and the Namespace can be found in the properties of your project:

Add the Webpart to the Webpartgallery

Go to the Webpartgallery from your sitecollection, and add the new Webpart to your Webpartgallery.

Now you are done J You can add the new Webpart to every site in your sitecollection.

Debug the Webpart

To be able to debug a Webpart, you have to copy the dll (which was compiled in debug mode) and the pdb to the bin folder of your virtual server.

The easiest way is to set the output path for your debug configuration in the VS to the bin folder (step one from this post).

  1. Set the output path

  1. Build your Webpart
  2. Attach the VS to the Application Pool which the SharePoint site uses
    If you are unsure which w3wp you should attach the VS to, you can look it up in the IIS Manager. You can find the user in the application settings from your virtual server.

 

 

 

 

  1. Set a breakpoint and reload the site in your browser

Caution:

  • Every time you deploy your Webpart, the application pool will recycle. So deploy with care, or – better – use a testsystem to develop and test your webparts.
  • While your breakpoint is active, the whole application pool will stop executing requests to every website, which uses that application pool.

Create a simple Webpart HOWTO

In this blog post, I want to show you how to create a simple Webpart. All you need is a Visual Studio 2005 (e.g. the express version) and of course SharePoint.

  1. Start your VS and create a new "Class Library"
  2. Add a reference to the Microsoft.SharePoint.dll. We will create a SharePoint Webpart, to be able to add Properties.
  3. To display some text, override the render method. You have to create a reference to the Microsoft.Web.dll, and type using System.Web.UI;

namespace simple_Webpart_HOWTO

{

public class Class1:WebPart

{

protected override void Render(HtmlTextWriter writer)

{

writer.Write("I like SharePoint.");

}

}

}

  1. (optional) Rename Class1 to some better name like "simpleWebpart". In the solution Explorer you can rename Class1.dll to simpleWebpart.dll
  2. Add [assembly: AllowPartiallyTrustedCallers()] to the AssemblyInfo.cs
  3. Next, we will create a Key, to sign our Assembly and give it a strong name. Open the "Visual Studio 2005 Command Prompt" from the Startmenu.
    sn -k 1024 c:\temp\keypair.snk
  4. Add the created Keypair to your project, and configure it to be signed

    After you build your project, you can extract your public key token with:
    sn -T "C:\PathToYourProject\bin\debug\simple Webpart HOWTO.dll"
    In my case the token is 2e6fe95c9937e6f4

Caution:

  • ALWAYS put a try/catch block around your code, if it might generate an error. If you don’t, the whole page will display an error, instead of just your Webpart.

catch (Exception ex)

{

HtmlGenericControl errorControl = new HtmlGenericControl("DIV");

errorControl.Attributes.Add("style", "padding: 20px; margin: 20px; border-style: groove; background-color: #FFFFFF;");

errorControl.InnerHtml = "<IMG src=\"/_layouts/images/error16by16.gif\" border=\"0\"/>" + ex.ToString();

Controls.Add(errorControl);

}

You can download the solution here.

Wiki mit Bildern Update

Falls bei der Benutzung des Webparts ein Fehler wie:

Fehler bei der Anforderung des Berechtigungstyps Microsoft.SharePoint.Security.SharePointPermission, Microsoft.SharePoint.Security, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c.

auftritt, muss der Trustlevel in der web.config auf Full gesetzt werden.

<trust level="Full" originUrl="" />

Zum vollständigen Beitrag: http://www.hezser.de

Update 23. Apr 2008:

Ich habe eine neue Version bereitgestellt.

Sending Email from SharePoint

You can configure a task list, to send an email if you assign a task to somebody. This works fine if this somebody has an internal email address.

If you happen to have an account inside the environment of the SharePoint Server, and configure it to have an external email address, sending an email to this account might fail. In the SharePoint Logs there is an entry:

03/12/2007    14:40:42.29    OWSTIMER.EXE (0x059C)    0x14E8    Windows SharePoint Services    E-Mail    8gsf    High    #160009: Die E-Mail-Adresse ‘somebody@somewhere.tld’ ist unbekannt. (something like: the email address ‘somebody@somewhere.tld’ is unknown)

(if not, adjust your logging for email events)

To be able to send emails to recipients outside your environment, you have to grant your SharePoint Server the right to send emails in the virtual SMTP Server of your Exchange Server.

C#, fast assignment

Here is a short way to declare a variable and set a value according to a condition:

bool var = (something == true) ? true : false;

The long way would be:

bool var;
if (something == true)
{
    var = true;
}
else
{
    var = false;
}

I like the short way. You have to decide for yourself

Update:

This was a bad example. If you want to set a bool, just type:

bool var = something;

Webpart, Properties and default value

If you write a Webpart with custom properties, you have to take care of the default value.

[WebBrowsable(true),
DefaultValue("value"),
Personalizable(true),
WebDisplayName("some property"),
WebDescription("Description of the property")]
public
string PropertyName
{
get { return _ PropertyName; }
set { _ PropertyName = value; }
}

Please do not specify a default value, which you might actually use. The default property value will not be saved, if you choose to configure it with the default value!

Wiki mit Bildern

Bei einem Blog Eintrag kann man Bilder mit an den Eintrag anfügen. Dies ist jedoch bei der Wiki Vorlage der Windows SharePoint Services V3 nicht möglich.

Um dieses Manko zu beseitigen, habe ich ein Webpart geschrieben. Dieses wird in die editform.aspx der Wiki List eingebaut. Danach kann man bequem über die Pflegemaske der Wiki Einträge Bilder an einen Wiki Beitrag anfügen. Die Bilder werden automatisch in eine Bildbibliothek hochgeladen.

Installation:

  1. Kopieren der Assembly in das bin Verzeichnis des virtuellen Servers
  2. Registrieren des Webparts in der web.config
    <SafeControl Assembly="WikiWebpart, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b17a955c3eada4c1" Namespace="WikiWebpart" TypeName="*" Safe="True" />
  3. Hinzufügen des Webparts auf der editform.aspx (mit dem SharePoint Designer)
  4. Erstellen einer Bildbibliothek in der Wiki Site
    Wenn Sie mehrere Bildbibliotheken auf der Wiki Site haben, kann in den Webpart Eigenschaften eine Bildbibliothek eingetragen werden.

Hinweis:
Wenn ein Bild angefügt wird, wird der Beitrag nicht gespeichert. Deshalb immer erst ein Bild hochladen, und dann den Beitrag bearbeiten!

Download: WikiWebpart

Update:

Falls bei der Benutzung des Webparts ein Fehler wie:

Fehler bei der Anforderung des Berechtigungstyps Microsoft.SharePoint.Security.SharePointPermission, Microsoft.SharePoint.Security, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c.

auftritt, muss der Trustlevel in der web.config auf Full gesetzt werden.

<trust level="Full" originUrl="" />

Update:
Ich habe eine neue Version des Webparts veröffentlicht. Siehe hier.

Genehmigung ausstehend…

Über ein Portal sind diverse Dokumentenbibliotheken – in den Dokumente auf eine Genehmigung warten – verteilt.

Dieses Szenario wird vielen bekannt vorkommen. Ein Lösung habe ich vor einige Zeit geschrieben. Das Webpart zeigt alle die Dokumente an

  1. die auf eine Genehmigung warten
  2. bei denen der Besucher das Recht hat die Genehmigung durchzuführen

Die Lösung ist nicht die schönste, aber sie hat bei mir funktioniert. Und das übrigens für Windows SharePoint Services V2 und den SharePoint Portal Server.

  • In der Konfiguration des Webparts sollte der Account eingetragen werden, unter dem auch der Application Pool läuft
  • Die Installation des Webparts muss mit der Option "-globalinstall" erfolgen

Zum Download: NetatWork.notApproved.CAB