SharePoint: Find Field Control
In page code-behind I need to get a control related to some field. It’s considered the best practice is using of SPContext.Current.FormContext.FieldControlCollection. It’s an ArrayList that stores the field controls in the form. The code can look like the following:
public static FieldMetadata FindFieldControl(string fieldName) { if (SPContext.Current.FormContext != null) { foreach (Control control in SPContext.Current.FormContext.FieldControlCollection) { FieldMetadata formField = control as FieldMetadata; if (formField != null && string.Compare(formField.FieldName, fieldName, true) == 0) return formField; } } return null; }
But the problem is that this collection is still empty or filled short on some early stages of page life cycle. In the same time the required field control can be already in the page tree of controls (Page.Controls).
In my case to create a new list item we use a custom aspx-page. This aspx is very similar to the original SharePoint new-page for lists, the main difference is in the attribute Inherits in page declaration (<%@ Page … Inherits=”MyPageClass” … %>). Such approach allows us to do something in code-behind without redefinition of the standard html layout and, as the result, allows to have one page for many content types, because a set of field controls for every content type is still rendered by SharePoint infrastructure. But let’s get back on track.
Let’s see the following example:
public class MyPageClass : WebPartPage { protected override void OnInitComplete(EventArgs e) { FieldMetadata fldTmp = FindFieldControl("Model"); // fldTmp = null, because the field control isn't created yet, SPContext.Current.FormContext.FieldControlCollection is empty base.OnInitComplete(e); fldTmp = FindFieldControl("Model"); // fld = null, SPContext.Current.FormContext.FieldControlCollection isn't empty, but it doesn't contain the required field control, // in the same time the required field control is already in page tree of controls (Page.Controls) } protected override void OnLoad(EventArgs e) { FieldMetadata fldTmp = FindFieldControl("Model"); // fld = null, SPContext.Current.FormContext.FieldControlCollection still doesn't contain the required field control, // but the required field control is presented in page tree of controls (Page.Controls) base.OnLoad(e); fldTmp = FindFieldControl("Model"); // finally, fldTmp isn't null, SPContext.Current.FormContext.FieldControlCollection contains the required field control } }
Obviously, to get the field control as earlier as possible, we can use page tree of controls. It can be implemented in this way:
public static FieldMetadata FindFieldControlRecursive(Control root, string fieldName) { FieldMetadata fieldMetadata = root as FieldMetadata; if (fieldMetadata != null && string.Compare(fieldMetadata.FieldName, fieldName, true) == 0) return fieldMetadata; foreach (Control c in root.Controls) { FieldMetadata t = FindFieldControlRecursive(c, fieldName); if (t != null) return t; } return null; }
The minus of this method is that it’s a recursive method and requires more time than if we use SPContext.Current.FormContext.FieldControlCollection. But we have to use FindFieldControlRecursive, if we need to get field controls at the early stage of page life cycle.
The better way is to combine two these approaches into one method. The result looks like the following:
public static FieldMetadata FindFieldControl(Control root, string fieldName) { if (SPContext.Current.FormContext != null) { foreach (Control control in SPContext.Current.FormContext.FieldControlCollection) { FieldMetadata formField = control as FieldMetadata; if (formField != null && string.Compare(formField.FieldName, fieldName, true) == 0) return formField; } } return FindFieldControlRecursive(root, fieldName); } public static FieldMetadata FindFieldControlRecursive(Control root, string fieldName) { FieldMetadata fieldMetadata = root as FieldMetadata; if (fieldMetadata != null && string.Compare(fieldMetadata.FieldName, fieldName, true) == 0) return fieldMetadata; foreach (Control c in root.Controls) { FieldMetadata t = FindFieldControlRecursive(c, fieldName); if (t != null) return t; } return null; }
After this we will have
public class MyPageClass : WebPartPage { protected override void OnInitComplete(EventArgs e) { FieldMetadata fldTmp = FindFieldControl(this, "Model"); // fldTmp = null, because the field control isn't created yet base.OnInitComplete(e); fldTmp = FindFieldControl(this, "Model"); // fldTmp isn't null, fldTmp was found in page tree of controls (Page.Controls) } protected override void OnLoad(EventArgs e) { FieldMetadata fldTmp = FindFieldControl(this, "Model"); // fldTmp isn't null, fldTmp was found in page tree of controls (Page.Controls) base.OnLoad(e); fldTmp = FindFieldControl(this, "Model"); // fldTmp isn't null, fldTmp was found in SPContext.Current.FormContext.FieldControlCollection } }
Don’t forget to use Static field name, do not use Display name. Thanks for attention!