Tuesday, January 26, 2010

SharePoint Limit Of 11 Direct Dependencies

MOSS 2007 Error

"An error occurred during the process of . The page '/_catalogs/masterpage/Support.master' allows a limit of 11 direct dependencies, and that limit has been exceeded.":




Resolution

Search following default setting in web.config:
    <SafeMode MaxControls="200" CallStack="false" DirectFileDependencies="10" 
TotalFileDependencies="50" AllowPageLevelTrace="false">
<PageParserPaths>
</PageParserPaths>
</SafeMode>
Change DirectFileDependencies value from 10 to a bigger number.

Monday, January 11, 2010

Custom Properties In SharePoint Custom Field Type

There are quite a lot of discussions in Internet regarding how to create custom field type in SharePoint with custom properties. Some are not working and some are way more too complicated.

I found the best and the easiest way to do this is use WSPBuilder which can be downloaded at http://wspbuilder.codeplex.com. It's a free tool for SharePoint and it simplifies the SharePoint development.

Once WSPBuilder is installed, Visual Studio 2005/2008 will include WSPBuilder extension menu context. To create a custom field type, first you create a WSPBuilder project, and right click the project to add a new item of "Custom Field Type"; then all those the field control, field editor control, field type definition xml, and field type classes, are all well created in certain folder. Under the FieldTypeCode folder, there's a CustomFieldType.cs class where the custom field type is defined. This field type class also includes a custom property. In order to add a new custom property, simply add a regular .NET property and add the its names to a static string array named "CustomPropertyNames", then all done! It works like a charm.

Carsten Keutmann is the creator of WSPBuilder. He seems to have very deep understanding of SharePoint. Another very popular free SharePoint utility, SharePoint Manager 2007, is also written by him. Microsoft really should consider to hire such genius people from the community.

The default CustomeFiledTyp.cs generated by WSPBuilder:
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using System.Web.UI;
using System.Web.UI.WebControls;


namespace WSPBuilderProject1
{
public class CustomFieldType1 : SPFieldText
{
private static string[] CustomPropertyNames = new string[] { "MyCustomProperty" };

public CustomFieldType1(SPFieldCollection fields, string fieldName)
: base(fields, fieldName)
{
InitProperties();
}

public CustomFieldType1(SPFieldCollection fields, string typeName, string displayName)
: base(fields, typeName, displayName)
{
InitProperties();
}

#region Property storage and bug workarounds - do not edit

/// <summary>
/// Indicates that the field is being created rather than edited. This is necessary to
/// work around some bugs in field creation.
/// </summary>
public bool IsNew
{
get { return _IsNew; }
set { _IsNew = value; }
}
private bool _IsNew = false;

/// <summary>
/// Backing fields for custom properties. Using a dictionary to make it easier to abstract
/// details of working around SharePoint bugs.
/// </summary>
private Dictionary<string, string> CustomProperties = new Dictionary<string, string>();

/// <summary>
/// Static store to transfer custom properties between instances. This is needed to allow
/// correct saving of custom properties when a field is created - the custom property
/// implementation is not used by any out of box SharePoint features so is really buggy.
/// </summary>
private static Dictionary<string, string> CustomPropertiesForNewFields = new Dictionary<string, string>();

/// <summary>
/// Initialise backing fields from base property store
/// </summary>
private void InitProperties()
{
foreach (string propertyName in CustomPropertyNames)
{
CustomProperties[propertyName] = base.GetCustomProperty(propertyName) + "";
}
}

/// <summary>
/// Take properties from either the backing fields or the static store and
/// put them in the base property store
/// </summary>
private void SaveProperties()
{
foreach (string propertyName in CustomPropertyNames)
{
base.SetCustomProperty(propertyName, GetCustomProperty(propertyName));
}
}

/// <summary>
/// Get an identifier for the field being added/edited that will be unique even if
/// another user is editing a property of the same name.
/// </summary>
/// <param name="propertyName"></param>
/// <returns></returns>
private string GetCacheKey(string propertyName)
{
return SPContext.Current.GetHashCode() + "_"
+ (ParentList == null ? "SITE" : ParentList.ID.ToString()) + "_" + propertyName;
}

/// <summary>
/// Replace the buggy base implementation of SetCustomProperty
/// </summary>
/// <param name="propertyName"></param>
/// <param name="propertyValue"></param>
new public void SetCustomProperty(string propertyName, object propertyValue)
{
if (IsNew)
{
// field is being added - need to put property in cache
CustomPropertiesForNewFields[GetCacheKey(propertyName)] = propertyValue + "";
}

CustomProperties[propertyName] = propertyValue + "";
}

/// <summary>
/// Replace the buggy base implementation of GetCustomProperty
/// </summary>
/// <param name="propertyName"></param>
/// <param name="propertyValue"></param>
new public object GetCustomProperty(string propertyName)
{
if (!IsNew && CustomPropertiesForNewFields.ContainsKey(GetCacheKey(propertyName)))
{
string s = CustomPropertiesForNewFields[GetCacheKey(propertyName)];
CustomPropertiesForNewFields.Remove(GetCacheKey(propertyName));
CustomProperties[propertyName] = s;
return s;
}
else
{
return CustomProperties[propertyName];
}
}

/// <summary>
/// Called when a field is created. Without this, update is not called and custom properties
/// are not saved.
/// </summary>
/// <param name="op"></param>
public override void OnAdded(SPAddFieldOptions op)
{
base.OnAdded(op);
Update();
}
#endregion

public override BaseFieldControl FieldRenderingControl
{
get
{
BaseFieldControl fieldControl = new CustomFieldType1Control(this);
fieldControl.FieldName = InternalName;
return fieldControl;
}
}

public override void Update()
{
SaveProperties();
base.Update();
}

public string MyCustomProperty
{
get { return this.GetCustomProperty("MyCustomProperty") + ""; }
set { this.SetCustomProperty("MyCustomProperty", value); }
}
}
}