Only readers following my blog from the beginning may remember my post I wrote about the deployment of custom fields having custom properties more than three years ago. Of course that post is about WSS 3.0.
At that time I described how to include the custom properties into the field definition even if these properties are not declared by the XSD validation schema. However, injecting the custom properties the way I described there did not have effect on the values of the custom properties the custom field actually deployed with. I promised then that in the next part I would show you how to resolve this issue. It’s better late than never, the second part comes now, updated for SharePoint 2010.
The trick to achieve our goal seemed originally to be really simple. The base idea behind it was that an instance of the field must be created sooner or later before usage, and the values we would like to push into the custom properties were available on object creation in the field schema deployed.
I’ve modified the constructors of the custom field, adding a call to my custom InitializeProps method.
- public SPFieldRegEx(SPFieldCollection fields, string fieldName)
- : base(fields, fieldName)
- {
- InitializeProps();
- }
- public SPFieldRegEx(SPFieldCollection fields, string typeName, string displayName)
- : base(fields, typeName, displayName)
- {
- InitializeProps();
- }
The InitializeProps method is responsible for reading up the deployed custom property values from the field schema and setting them to the standard custom location in the schema.
- // in the custom field feature definition
- private readonly string customNamespaceUri = "http://schemas.grepton.com/sharepoint/";
- private void InitializeProps()
- {
- String regEx = (String)GetCustomProperty("RegEx");
- // value of custom property is null if not yet set
- if (regEx == null)
- {
- // load the field schema into an XML document
- XmlDocument schemaXml = new XmlDocument();
- schemaXml.LoadXml(SchemaXml);
- XmlNode fieldNode = schemaXml.SelectSingleNode("Field");
- if (fieldNode != null)
- {
- InitCustomProperty(fieldNode, "RegEx");
- InitCustomProperty(fieldNode, "ErrMsg");
- InitCustomProperty(fieldNode, "MaxLen");
- }
- }
- }
- private void InitCustomProperty(XmlNode fieldNode, String custPropName)
- {
- XmlAttribute custPropOrigAttr = fieldNode.Attributes[custPropName, customNamespaceUri];
- // should not be null, but we check it
- if (custPropOrigAttr != null)
- {
- SetCustomProperty(custPropName, custPropOrigAttr.Value);
- }
- }
After deploying my custom field, I’ve checked my field at the Change Site Column page and was happy to see my custom property values there:
However, it turned out quickly that the schema of my field was not updated as expected:
- <Field
- ID="{54634385-A8AC-4898-BF24-E533EB23444F}"
- Name="RegExField"
- DisplayName="RegExField"
- StaticName="RegExField"
- Group="Grepton Fields"
- Type="SPFieldRegEx"
- Sealed="FALSE"
- AllowDeletion="TRUE"
- SourceID="http://schemas.microsoft.com/sharepoint/v3/fields"
- Description="This is the RegEx field"
- grp:RegEx="[0-9]"
- grp:MaxLen="20"
- grp:ErrMsg="Error!"
- xmlns:grp="http://schemas.grepton.com/sharepoint/" />
Of course, pressing OK on the Change Site Column page updated the field schema with the custom properties:
- <Field
- ID="{54634385-A8AC-4898-BF24-E533EB23444F}"
- Name="RegExField"
- DisplayName="RegExField"
- StaticName="RegExField"
- Group="Grepton Fields"
- Type="SPFieldRegEx"
- Sealed="FALSE"
- AllowDeletion="TRUE"
- SourceID="http://schemas.microsoft.com/sharepoint/v3/fields"
- Description="This is the RegEx field"
- grp:RegEx="[0-9]"
- grp:MaxLen="20"
- grp:ErrMsg="Error!"
- xmlns:grp="http://schemas.grepton.com/sharepoint/"
- Required="FALSE"
- EnforceUniqueValues="FALSE"
- Version="1">
- <Customization>
- <ArrayOfProperty>
- <Property>
- <Name>RegEx</Name>
- <Value
- xmlns:q1="http://www.w3.org/2001/XMLSchema"
- p4:type="q1:string"
- xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">[0-9]</Value>
- </Property>
- <Property>
- <Name>MaxLen</Name>
- <Value
- xmlns:q2="http://www.w3.org/2001/XMLSchema"
- p4:type="q2:double"
- xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">20</Value>
- </Property>
- <Property>
- <Name>ErrMsg</Name>
- <Value
- xmlns:q3="http://www.w3.org/2001/XMLSchema"
- p4:type="q3:string"
- xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">Error!</Value>
- </Property>
- </ArrayOfProperty>
- </Customization>
- </Field>
That gave me the idea that I should try to deploy my custom field using this schema. I removed my custom attributes from the Field element and used the following XML to deploy the field.
- <?xml version="1.0" encoding="utf-8" ?>
- <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
- <Field
- ID="{54634385-A8AC-4898-BF24-E533EB23444F}"
- Name="RegExField"
- DisplayName="RegExField"
- StaticName="RegExField"
- Group="Grepton Fields"
- Type="SPFieldRegEx"
- Sealed="FALSE"
- AllowDeletion="TRUE"
- SourceID="http://schemas.microsoft.com/sharepoint/v3/fields"
- Description="This is the RegEx field"
- Version="1">
- <Customization>
- <ArrayOfProperty>
- <Property>
- <Name>RegEx</Name>
- <Value
- xmlns:q1="http://www.w3.org/2001/XMLSchema"
- p4:type="q1:string"
- xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">[0-9]</Value>
- </Property>
- <Property>
- <Name>MaxLen</Name>
- <Value
- xmlns:q2="http://www.w3.org/2001/XMLSchema"
- p4:type="q2:double"
- xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">20</Value>
- </Property>
- <Property>
- <Name>ErrMsg</Name>
- <Value
- xmlns:q3="http://www.w3.org/2001/XMLSchema"
- p4:type="q3:string"
- xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">Error!</Value>
- </Property>
- </ArrayOfProperty>
- </Customization>
- </Field>
- </Elements>
I’ve removed my custom codes described above either, and tried to deploy the field.
Voilà! The field is deployed successfully, including the custom properties. At that point I really don’t understand if it would work for WSS 3.0 and if so, how I missed to find that solution three years ago. The main point it is working now and requires no hacking at all.
A mystical observation is that after deploying the field I was not able to get a reference for the new field using PowerShell:
$avFields = $web.AvailableFields
$avFields["RegExField"]
At the same time, the field is visible on the web UI, and the following C# code finds it:
SPFieldCollection avFields = web.AvailableFields;
SPField field = avFields["RegExField"];
If I create the field from code, PowerShell finds that either:
SPFieldCollection fields = web.Fields;
SPField fieldCode = new SPField(fields, "SPFieldRegEx", "RegExCode");
fields.Add(fieldCode);
If you know the reason for that, let me know, please!