AddFieldAsXml cannot be used to set the InternalName correctly
All fields in SharePoint lists (and doclibs which are specialized lists) have two names. An Internal Name that's used by SharePoint and the Object Model (among other things) and an Display Name which is what you see in your Browser. There are four ways you can create a new field on a list in SharePoint.
- Simply use the Web Interface and add a new column. When you add the column, the name you give it at creation time is set as both the Internal Name and the Display Name. Anytime after that when you change the name you're only changing the Display Name.
- Create a custom site definition with SCHEMA.XML. Here you can set both the Internal Name and Display Name but the user would be able (with the right privledges) to change the Display Name.
- Create a field using the AddField method of the SPFieldCollection class. Here you can only set the Display Name. The Internal Name will get autogenerated by SharePoint so you have no control over it. There are rules around what that Internal Name will be and you could write your own routine to figure that out, but that's beyond the scope of this posting.
- Create a field using the AddFieldAsXml method of the SPFieldCollection class. Here it's the same thing as the previous method but you specify the CAML for the field (same CAML as you would specify in a SCHEMA.XML file). This has the most flexiblity but also has a bug which is the point of this post.
The Problem
So you decide you're going to dynamically update a list using a snippet of CAML and make a call to the AddFieldAsXml method. Let's say your CAML looks something like this:
string
newField = "<Field Type=\"Text\" "DisplayName=\"New_Field_Display_Name\" "Name=\"New_Field_Internal_Name\"/>";myFieldCollection.AddFieldAsXml(newField);
So you expect to create a field with a Display Name of "New_Field_Display_Name" and an internal name of "New_Field_Internal_Name" right? Wrong. After the method call you take a look at the field. Lo and behold, SharePoint has basically ignored your request to make the internal name "New_Field_Internal_Name" and instead set it to "New_Field_Display_Name". Blech! That's NOT what I asked for.
The Fix
The fix is a little two-step that you have to do with SharePoint to get the desired result when using the AddFieldAsXml method:
- Define your CAML so that the Internal Name you want to use is actually set as the Display Name
- Create the field with the call to AddFieldAsXml
- After the field is created, retrieve it using the internal name and set the Title property to the real Display Name you wanted it to be in the first place
So a simple little snippet to do this would be (this assumes you have some CAML and a SPFieldCollection first):
/// <summary>
/// Adds a field as XML to a SharePoint field collection. This fixes the AddFieldAsXml bug SharePoint has.
/// </summary>
/// <param name="fields">Field collection to add the new field to.</param>
private void AddFieldAsXml(SPFieldCollection fields)
{
// Declare our intent for our names here
string internalName = "New_Field_Internal_Name";
string displayName = "New_Field_Display_Name";
// Our definition for the CAML. Note that DisplayName is really our internal name here
string newField = "<Field Type=\"Text\" DisplayName=\"New_Field_Internal_Name\" Name=\"New_Field_Internal_Name\"/>";
// Call the SharePoint method to create the field.
fields.AddFieldAsXml(newField);
// Retrieve the newly created field using the internal name
SPField field = fields[internalName];
// Reset the title to the name we want it to be (after AddFieldAsXml the display name will be the internal name)
field.Title = displayName;
// Finally commit the updates to the field
field.Update();
}
Feel free to use this and update it (maybe passing in the field names or even put it into a class). Hope that helps. Many thanks to Brian on our team for coming up with a solution.