Tuesday, November 15, 2011

How to add a survey list to the Quicklaunch

When you add a survey list to a site using a webtemplate or sitetemplate you add the following line to the onet.xml:

<List FeatureId="00bfea71-eb8a-40b1-80c7-506be7590102" Type="102" Title="$Resources:core,surveyList;" Url="$Resources:core,lists_Folder;/$Resources:core,surveyList;" QuickLaunchUrl="$Resources:core,lists_Folder;/$Resources:core,surveyList;/overview.aspx" />

When you create a site with this onet.xml the survey list is created however it’s not added to the quicklaunch. This is probably because the <Navbars> doesn’t contain a ‘Survey’ category.

To fix this add this line to the <Navbars> element:

<NavBar Name="$Resources:core,category_Surveys;" Prefix="&lt;table border='0' cellpadding='4' cellspacing='0'&gt;" Body="&lt;tr&gt;&lt;td&gt;&lt;table border='0' cellpadding='0' cellspacing='0'&gt;&lt;tr&gt;&lt;td&gt;&lt;img src='/_layouts/images/blank.gif' id='100' alt='' border='0'&gt;&amp;nbsp;&lt;/td&gt;&lt;td valign='top'&gt;&lt;a id='onetleftnavbar#LABEL_ID#' href='#URL#'&gt;#LABEL#&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/td&gt;&lt;/tr&gt;" Suffix="&lt;/table&gt;" ID="1007" />

Or you could use one of the alternatives:
- Add the survey list in code (web.Lists.Add with SPListTemplateType.Survey) and set OnQuickLaunch to true.
- manually add the survey list to the quicklaunch using the List Settings –> Title, description and navigation. The Navbar item will be added automatically.

Wednesday, October 19, 2011

Deploy files to Pages subfolder (SharePoint 2010)

Deploy pages/files to a subfolder in the pages library.

How it’s done:
In Visual Studio 2010 create a module:


with the following elements.xml

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<Module Name="AdminPages" Url="$Resources:osrvcore,List_Pages_UrlName;/AdminPages" Path="AdminPages">
<File Path="ChangePassword.aspx" Url="ChangePassword.aspx" Type="GhostableInLibrary" />
<File Path="ForgotPassword.aspx" Url="ForgotPassword.aspx" Type="GhostableInLibrary" />

Some explanation about the elements file:
Module.Name: name of the module
Module.Url: location in SharePoint, where do you want to deploy the files to.
Module.Path: location of the files in your feature (In this case in VS2010 the ‘AdminPages’ module creates a directory in the feature with name ‘AdminPages’)
File.Path: location of the file in your feature (it also uses the Module.Path, so don’t add the ‘AdminPages’ because it’s defined in the Module.Path)
File.Url: filename in SharePoint (you could name the file whatever you like)
Add the module to a feature.
Deploy the solution.

After installing and activating the feature (that contains the AdminPages module) you will see that a folder ‘AdminPages’ is created in the /Pages (depending on language) folder.



Friday, June 24, 2011

Reminders for Continuous build for SharePoint projects in Team Foundation Server (TFS)

Based on this MSDN article How to Build SharePoint Projects with TFS Team Build I setup the build machine. When doing so and tested it on my current SharePoint 2010 project I found some issues. As a reminder-to-self here some notes:

Deployment of DLLs to GAC

Some dll’s should be deployed to GAC. Use gacutil (of the .NET 4 framework) to do this, using a .NET 2 or 3.5 version doesn’t work.

- Download and install the Microsoft Windows SDK for Windows 7 and .NET Framework 4
- Gacutil location for 64bit systems is C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\NETFX 4.0 Tools\

SharePoint DLLs

Copy all SharePoint dll’s from the C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\ISAPI\
When your SharePoint project references Microsoft.SharePoint.Publishing, also copy System.Web.DataVisualization.dll (.NET 3.5). It location is C:\Program Files (x86)\Microsoft Chart Controls\Assemblies\ This is because the publishing assembly references the DataVisualization assembly.

Updating SharePoint 2010

When installing cumulative or Service Packs on SharePoint 2010, you need to update the dll’s on your build server to keep them aligned.

Thursday, June 23, 2011

SharePoint 2010 Workflow: Could not load file or assembly '$assemblyname$'

During workflow development I got the following error when starting a Site workflow:

Load Workflow Assembly: System.IO.FileNotFoundException:
Could not load file or assembly '$assemblyname$' or one of its dependencies. The system cannot find the file specified. File name: '$assemblyname$'

Very strange, it did worked for months. So I checked the workflow feature in the 14-hive. The element manifest was wrong. It contained the $assemblyname$ tag instead of the assembly name.

Name="Ctalk - MailCtalkEditieWF"
Description="Workflow for sending Ctalk Editions"

After a ‘normal’ deployment in VS2010 the element manifest file was correct:

Name="Ctalk - MailCtalkEditieWF"
Description="Workflow for sending Ctalk Editions"
CodeBesideAssembly="Ctac.Ctalk, Version=, Culture=neutral, PublicKeyToken=6a509658686505f0">

So what was the problem… It’s the VS2010 ‘Copy to SharePoint Root’ command part of the CKSDev extension. It just copied the file as is, it doesn’t replace the tag. So keep this in mind when using the ‘Copy to SharePoint Root’ command in combination with workflow development.

Wednesday, June 22, 2011

Provisioning URL values with description using element manifest

When provisioning files/items that contain an URL typed field you probably want to provide an url and description. When using an element manifest to provision some content you probably use something like this:

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<Module Name="Banners" Url="Banners">
<File Path="Banners\banner1.png" Url="banner1.png" Type="GhostableInLibrary">
<Property Name="URL" Type="string" Value="http://www.yellowred.nl"/>
<Property Name="NewWindow" Value="true"/>
There’s no room for providing a description. The property element has the following ‘Type’ attribute options: int, string, datetime. So no url type.

As you know the URL value is just a string with in specific format: <url>, <description>
You can also find this format when using SharePoint Manager 2010. Open the item containing the url field. Check the schema.xml and search for the url.

To provide a description to the url, provision your data like this:

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<Module Name="Banners" Url="Banners">
<File Path="Banners\banner1.png" Url="banner1.png" Type="GhostableInLibrary">
<Property Name="URL" Type="string" Value="http://www.yellowred.nl, Yellow and Red"/>
<Property Name="NewWindow" Value="true"/>

Friday, June 3, 2011

Issues with RemoveFieldRef and ContentTypes

When inheriting from content types you can use RemoveFieldRef to remove unused fields. The RemoveFieldRef however is very picky when you want it to work.

Example content type “SampleInheritance” (inherits from content type: Event (0x0102))

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
Description="Create a new meeting, deadline or other event."
<FieldRef ID="fce16b4c-fe53-4793-aaab-b4892e736d15" Name="EMail" DisplayName="E-Mail" />
<FieldRef ID="114bf263-2846-4854-839b-715c0f573cea" Name="Header1" DisplayName="Header" />
<FieldRef ID="f9589629-6f74-403e-83f6-8da3316dcca2" Name="BedankPagina" DisplayName="BedankPagina" />
<RemoveFieldRef ID="{7d95d1f4-f5fd-4a70-90cd-b35abc9b5bc8}"/>
<XmlDocuments xmlns="http://schemas.microsoft.com/sharepoint/">
<XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
<FormTemplates xmlns="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">

Follow these rules:

  1. in <RemoveFieldRef> the GUID in the ID should start with ‘{‘ and ends with ‘}’
  2. in <RemoveFieldRef> the GUID in the ID must be lowercase
  3. set "Inherits=false” or remove the attribute.

Wednesday, February 23, 2011

Programmatically connect two ListViewWebParts to Filter based on value of Provider Web Part

When you want to connect two ListViewWebParts on a page using the user interface is easy. However doing it programmatically was a bit more complicated. It’s not complex, but you need to know what classes you need to use.

Connecting Web Parts using the User interface:

Select the provider Web Part and connect to the consumer web part with the ‘Send Row of Data To’ option.

Step 1:
Configure the connection on the Consumer Web Part.
Select ‘Get Filter Values From’


Step 2:
Provider Field Name: Title(linked to item)
Consumer Field Name: ArticleEditionTitle

The provider and consumer field names are dependent on your needs. In this case the value of the Title of the provider Web Part is passed to the consumer web part. The consumer web part will only show rows where ArticleEditionTitle is equal to the passed value.

 Connecting Web Parts programmatically:
Use the SPRowToParametersTransformer class, provide the correct provider and consumer fieldnames. These fields are the same as the ones used in step 2 of the user interface procedure.

SPRowToParametersTransformer transformer = new SPRowToParametersTransformer();
transformer.ProviderFieldNames = new string[] { "LinkTitleNoMenu" };
transformer.ConsumerFieldNames = new string[] { "ArticleEditionTitle" };

Get the WebParts that need to get connected
string providerWebPartTitle = "Editions";
string consumerWebPartTitle = "Articles";

WebPart providerPart = (from WebPart w in mgr.WebParts where w.Title == providerWebPartTitle select w).FirstOrDefault();
WebPart consumerPart = (from WebPart w in mgr.WebParts where w.Title == consumerWebPartTitle select w).FirstOrDefault();

Determine the ConnectionPoints of the webparts. Note the provider/consumer ConnectionIds
string providerConnectionId = "DFWP Row Provider ID";
string consumerConnectionId = "DFWP Filter Consumer ID";

//get connectionpoints
ProviderConnectionPoint providerConnectionPoint = (from ProviderConnectionPoint conn in manager.GetProviderConnectionPoints(providerPart)
where conn.ID == providerConnectionId
select conn).FirstOrDefault();

ConsumerConnectionPoint consumerConnectionPoint = (from ConsumerConnectionPoint conn in manager.GetConsumerConnectionPoints(consumerPart)
where conn.ID == consumerConnectionId
select conn).FirstOrDefault();

Add a WebPartConnection using WebPartManager.SPConnectWebParts, and pass along the transformer.

// connect the webparts
manager.SPConnectWebParts(providerPart, providerConnectionPoint, consumerPart, consumerConnectionPoint, transformer);

That’s it.

Friday, February 18, 2011

Add SPNavigation Heading without link functionality to QuickLaunch

Adding items to the Quicklaunch or TopNavigation is easy. However adding a heading to the Quicklaunch without the link functionality is not possible by using the basic SharePoint 2010 API. In this post I’ll show you how to create a navigation item, transform it into a heading without link functionality, and add it to the Quicklaunch.

The options:

  1. Create a SPNavigationNode
    add it to navigation using spWeb.Navigation.AddToQuickLaunch(SPNavigationNode node, SPQuickLaunchHeading heading), where heading is an enum of some default SP2010 headings.
  2. Create a SPNavigationNode
    Get SPNavigationNodeCollection from spWeb.Navigation.QuickLaunch
    Add SPNavigationNode to the SPNavigationNodeCollection using methods like AddAsFirst, or AddAsLast

As option 1 can only to add items to default SP2010 headings. So we need to go for option 2.

The problem
Option 2 can only add a heading navigation node to the quicklaunch that has a link. When you use the following code it will create a heading, however it will link to the ‘base url’ of the current SPWeb.

// Create the node.
SPNavigationNodeCollection quicklaunchNav = web.Navigation.QuickLaunch;

// Create heading
SPNavigationNode headerNode = new SPNavigationNode(headerTitle, string.Empty, true);
headerNode = quicklaunchNav.AddAsLast(headerNode);

// Add subnode to heading.
SPNavigationNode node = new SPNavigationNode("title", "url", true);

 The Solution
The difference between a navigation item and a heading navigation item are some value in the NavigationNode.Properties HashTable.

To create a heading use the following code.

public static class SPNavigationNodeExtensions
public static void MakeHeaderNode(this SPNavigationNode node)
node.Properties["BlankUrl"] = "True";
node.Properties["LastModifiedDate"] = DateTime.Now;
node.Properties["Target"] = "";
node.Properties["vti_navsequencechild"] = "true";
node.Properties["UrlQueryString"] = "";
node.Properties["CreatedDate"] = DateTime.Now;
node.Properties["Description"] = "";
node.Properties["UrlFragment"] = "";
node.Properties["NodeType"] = "Heading";
node.Properties["Audience"] = "";

As you can see, the “BlankUrl'” = True, and NodeType = “Heading”. Using the Update method it saves changes of the properties.
It’s now possible to transform the heading node using this extension method.
//Transform Node into Header.

The final code is:

// Create the node.
SPNavigationNodeCollection quicklaunchNav = web.Navigation.QuickLaunch;

// Create heading
SPNavigationNode headerNode = new SPNavigationNode("HeadingTitle", string.Empty, true);
headerNode = quicklaunchNav.AddAsLast(headerNode);

//Transform Node into Header.

// Add subnode to heading.
SPNavigationNode node = new SPNavigationNode("title", "url", true);

At this point you’ll have a heading with '”HeadingTitle” that doesn’t link. It has a sub navigation item “title”, that links to “url”. Also thanks to Matthijs Woolderink (@MWoolderink) for some background information.

Wednesday, February 16, 2011

Reminder about Content Types

When constructing a ContentType in the elements file you’ll reference to existing Site Columns.

Example Content Type:
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<ContentType ID="0x010055180D0A5202894F9E64FC9D6D4A86B7" Name="EditionCT" Group="Test" Inherits="true" Hidden="false" ReadOnly="false" Sealed="false">
<FieldRef ID="71316cea-40a0-49f3-8659-f0cefdbdbd4f" Name="ArticleStartDate" DisplayName="Article Date" />
<FieldRef ID="64cd368d-2f95-4bfc-a1f9-8d4324ecb007" Name="StartDate" DisplayName="Start Date" />
<FieldRef ID="919f30d5-31f1-478f-bda5-84f595340392" Name="EndDate1" DisplayName="End Date" />
<FieldRef ID="d2132670-ec6e-4fc7-af38-0ca09a364b80" Name="Send" DisplayName="Send" />
<FieldRef ID="8adac618-8387-4c39-ad9a-ed6c17084d3a" Name="Send_x0020_Date" DisplayName="Send Date" />
<FieldRef ID="d1fc4f17-b0f7-4177-9f94-5b32cbdd2d5a" Name="Send_x0020_To" DisplayName="Send To" />
<FieldRef ID="cc69c48f-5536-4478-9172-a79468a32afa" Name="FinalSubmissionDate" DisplayName="FinalSubmissionDate" />
<FieldRef ID="cd8a6351-3235-4eb2-857d-87975bb8cb90" Name="ReminderDays" DisplayName="ReminderDays" />
<FieldRef ID="bcf32df2-5191-43d7-a1a4-fdb17acccb98" Name="SendReminderAt" DisplayName="SendReminderAt" />
Example SiteColumn:
<Field Type="Boolean" DisplayName="Send" Group="Base" EnforceUniqueValues="FALSE" Indexed="FALSE" ID="{d2132670-ec6e-4fc7-af38-0ca09a364b80}" SourceID="{b6366c11-b4ce-408c-8175-952b9a7800d4}" StaticName="Send" Name="Send" ShowInNewForm="FALSE" ShowInEditForm="FALSE" />
One thing did cost me a few hours to find out. When activating the feature the Content Type EditionCT was corrupt. It showed the Send column was of type DateTime, it was defined as a Boolean. In the Site Column overview it did show as a boolean. So only the content type was corrupted.
Site Column:
Content Type in Site Settings (nothing wrong, you think):
Content Type in SharePoint Manager 2010 (its corrupt):
Content Type when added to a list (also corrupted):
Than I noticed the ArticleStartDate was a site column from the Publishing framework. This site collection feature wasn’t activated and so that appropriate fields were not available, one of them was the ArticleStartDate. Strange thing was that SharePoint didn’t report an error when constructing the content type, but just corrupted the Content Type.
So keep in mind to have the fields available when provisioning the Content Type, and as you can see, strange things can happen.

Sunday, February 13, 2011

How to Customize the SharePoint List "NewForm" using VS2010 instead of SharePoint Designer

Most blogs show you how to customize the NewForm of a SharePoint List by using SharePoint Designer. However when you need to support/maintain a SharePoint Solution you really should use a Solution (.wsp). Easiest way is to use VS2010. In this blog I demonstrate how to create a customized NewForm, this means. When a user clicks 'New Item' in the list it will render a customized version of the 'New Form'. It's possible to add additional Web Parts and content. In this version it will however still use the default ListFormWebPart to render the new-item form.
I assume you already have created custom Fields (Site Columns) and Content Types in VS2010.
The steps to take are:
  1. Create ListDefinition
  2. (optional) Create ListInstance
  3. Create a custom page that will hold the customizations
  4. Customize ListDefinition schema
  5. Deploy the solution, activate feature
Step 1: Create ListDefinition
In VS2010, you have a choice to create a new ListDefinition based on Content Type and just a plain ListDefinition. In this demo I chose the latter.

I want to create a List Definition based on Custom list. I also create to create a List Instance (Step 2) so after deployment I immediately have a custom list created.

Step 3: Create a customized NewForm
In schema.xml of the ListDefinition you see this line:
<Form Type="NewForm" Url="NewForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" />
The SetupPath point to the 14-hive\templates folder. So In this case it will provision a NewForm.aspx based on the C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\Pages\form.aspx
You don't want to change this out-of-the-box page. It will void you support from Microsoft ;-).
So make a copy, copy it into the ListDefinition project and rename it to MyNewForm.aspx. Make sure you include MyNewForm.aspx into the VS2010 project and set the 'Deployment Type' to ElementFile, this will deployed the file to the feature directory. It should now look like this in VS2010.

Add some content to the NewForm:
Open the MyNewForm.aspx and look for the PlaceHolderMain ContentPlaceHolder (Line 244).
Put some content like <h1>Hello Customized World</h1> in front of the the <table …> a few line below.
Add a Web Part Zone to the NewForm:
Add: <WebPartPages:WebPartZone runat="server" FrameType="None" ID="Top" Title="loc:Top" /> after the <h1>Hello…

So it will look like this:
<asp:Content ContentPlaceHolderId="PlaceHolderMain" runat="server">
<SharePoint:UIVersionedContent UIVersion="4" runat="server">
    <div style="padding-left:5px">
    <h1>Hello Customized World</h1>
    <WebPartPages:WebPartZone runat="server" FrameType="None" ID="Top" Title="loc:Top" />
    <table cellpadding="0" cellspacing="0" id="onetIDListForm" style="width:100%">
     <WebPartPages:WebPartZone runat="server" FrameType="None" ID="Main" Title="loc:Main" />

Save the changes ;-).
Step 4 Change the Schema.xml
Now we have created a custom page, however we need to tell the ListDefinition to use the customize NewForm. To do this, we need to change the Form element in the ListDefinition schema.xml
Code Before:

<Form Type="NewForm" Url="NewForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" />

Code After:
<Form Type="NewForm" Url="NewForm.aspx" Path="MyNewForm.aspx" WebPartZoneID="Main" Default="TRUE" UseDefaultListFormWebPart="False" WebPartOrder="1">
    <AllUsersWebPart WebPartZoneID="Main" WebPartOrder="1">
    <WebPart xmlns="http://schemas.microsoft.com/WebPart/v2">
      <Assembly>Microsoft.SharePoint, Version=, Culture=neutral, PublicKeyToken=71e9bce111e9429c</Assembly>                         
    <AllUsersWebPart WebPartZoneID="Top" WebPartOrder="1">
    <WebPart xmlns="http://schemas.microsoft.com/WebPart/v2" xmlns:iwp="http://schemas.microsoft.com/WebPart/v2/Image">
      <Assembly>Microsoft.SharePoint, Version=, Culture=neutral, PublicKeyToken=71e9bce111e9429c</Assembly>
      <Title>My Custom Image</Title>

What I've done is:
  • instead of using the default /pages/form.aspx, I told it to use the MyNewForm.aspx (So I changed SetupPath="pages/form.aspx" to Path="MyNewForm.aspx", it should not look into the template directory but in the feature directory, so SetupPath => Path…). The file will still be accessible with url NewForm.aspx. You can change that if you want.
  • UseDefaultListFormWebPart="False", it will not add a default ListFormWebPart, but it will process the <WebParts> child elements.
  • The <WebParts> child elements are used to place web part on the Custom MyNewForm.aspx
    • first web part is a ListFormWebPart. When setting the PageType to PAGE_NEWFORM, it will add a ListFormWebPart that will handle the 'New Item' rendering, make sure the WebPartZoneID matches with the ZoneID's in the customized form. Default there's a Main ZoneID.
    • second web part is a Image Web Part, showing a default MS SharePoint logo. This web part will be placed in the Top WebPartZoneID (our custom WebPartZone).
Final Step: Deploy solution and activate feature.
Deploy the solution using VS2010.
Visit the site where you deployed the solution. If VS2010 didn't automatically activated the feature, you should go to Site Settings, Manage Site Features and look for feature 'CustomListDemo Feature1' (This is why a naming convention is recommended ;-)). So make sure it's activated.
As the feature included a listinstance a list is created. The list name is: "CustomListDemo - ListInstance1".
Go to this list and click on 'New Item'.
This will be the result:

As you can see. The custom NewForm, including some custom content, a custom Web Part and the default ListFormWebPart. This is just a simple example. But you could go wild on the content and on adding your own Web Parts. It's also possible to change the template the ListFormWebPart uses. But that's for another day…

Read some more about Customizing Form.
You can follow me on twitter

Thursday, February 3, 2011

Tombstoning MVVMLight ViewModels with an ApplicationBar using SilverlightSerializer

I've first implemented Tombstoning MVVMLight ViewModels using the default DataContractSerializer. I save the ViewModel when closing the application to persistent storage by using the IsolatedStorageSettings.ApplicationSettings. When deactivating the application I saved the ViewModels to transient storage using PhoneApplicationService.Current.State. This method has some limitations regarding maximum storage size. Second problem was that the MVVMLight ViewModelBase class constructor was not public and therefor could not be serialized. I fixed this by just downloading the sources and use the new assemblies.
I wasn't really satisfied. When I was at the DotNed meeting at Qurius there was a discussion about saving states and what serializers would be a good option. The SilverLightSerializer was the one I remembered, so back at home I did some digging and found that LocalJoost blogged about it.
I implemented the SilverLightSerializer and just needed to replace the saving and loading state parts. Than I tested the application and found out the application bar was gone after a deactivate / activate cycle.
Before deactivating:
Then do a 'Start' and 'Back', it will activate in a state like this:
I also had this problem before using the DataContractSerializer. That was fixed by decorating the public ApplicationBar properties with [IgnoreDataMember] attribute. The SilverLightSerializer skips properties from being serialized which are decorated with the [DoNotSerialize] attribute. So I replaced the [IgnoreDataMember] with [DoNotSerialize] and the ApplicationBar was back again.
Hopes this saved you some hours of searching and testing.

Sunday, January 16, 2011

Silverlight Toolbox GestureListener not working great when developing using Remote Desktop

The Silverlight for Windows Phone Toolkit is working fine in normal environments, great toolkit. However when I started developing WP7 apps in the living room and used a Remote Desktop connection to the development machine I encountered very bad gesture responses in the Windows 7 Emulator. The Flick gesture on the emulator screen didn't do anything (well about 1 out of 100). Doing it again 1 minute later on de development machine without RDS and it worked all the time. Other gestures worked fine. Maybe it's something with the mouse events?

The XAML code I used:

<toolkit:GestureListener Flick="GestureListener_Flick">

Code behind:

   1: if (ViewModel.ViewModelLocator.MainStatic.TossCmd.CanExecute(e))
   2: {
   3:     ViewModel.ViewModelLocator.MainStatic.TossCmd.Execute(e);
   4: }

Setting a breakpoint on line 1 never kicked in.

Friday, January 7, 2011

Property Bag issues

This time a minor blog post. It’s more for myself so I don’t forget.

This time it’s about the property bag in various object in SharePoint 2010. The problem I came across was how to remove a property bag key-value. But lets start at the beginning.

1- Add an value to the property bag.
//set value on (a new) Property bag 
if (web.Properties.ContainsKey("ExpireOn"))
web.Properties["ExpireOn"] = "some sting";
web.Properties.Add("ExpireOn","some string");

2- Remove an item from property bag

//Remove Property bag  
//Does not work

//Does work
web.Properties["ExpireOn"] = null;

As you can see, using Remove doesn’t work. You should set the value to null, call Update() on properties to persist the change to the database. At this point the null-ed Property bag key-value will be removed from the collection.