/// <summary> /// Generates the Field XML for a site column definition /// </summary> /// <param name="fieldInfo">The field definition for which we want to print out the full XML schema</param> /// <returns>The XML schema of the field</returns> public XElement SchemaForField(BaseFieldInfo fieldInfo) { var schema = new XElement( "Field", new XAttribute("Name", fieldInfo.InternalName), new XAttribute("Type", fieldInfo.FieldType), new XAttribute("ID", "{" + fieldInfo.Id + "}"), new XAttribute("StaticName", fieldInfo.InternalName), new XAttribute("DisplayName", this.resourceLocator.GetResourceString(fieldInfo.ResourceFileName, fieldInfo.DisplayNameResourceKey)), new XAttribute("Description", this.resourceLocator.GetResourceString(fieldInfo.ResourceFileName, fieldInfo.DescriptionResourceKey)), new XAttribute("Group", this.resourceLocator.GetResourceString(fieldInfo.ResourceFileName, fieldInfo.GroupResourceKey))); // Check the Required type if (fieldInfo.Required == RequiredType.Required) { schema.Add(new XAttribute("Required", "TRUE")); } if (fieldInfo.Required == RequiredType.NotRequired) { schema.Add(new XAttribute("Required", "FALSE")); } // Hidden state if (fieldInfo.IsHidden) { schema.Add(new XAttribute("Hidden", "TRUE")); } // Show in Display Form if (fieldInfo.IsHiddenInDisplayForm) { schema.Add(new XAttribute("ShowInDisplayForm", "FALSE")); } // Show in Edit Form if (fieldInfo.IsHiddenInEditForm) { schema.Add(new XAttribute("ShowInEditForm", "FALSE")); } // Show in new Form if (fieldInfo.IsHiddenInNewForm) { schema.Add(new XAttribute("ShowInNewForm", "FALSE")); } // Show in List settings if (fieldInfo.IsHiddenInListSettings) { schema.Add(new XAttribute("ShowInListSettings", "FALSE")); } else { schema.Add(new XAttribute("ShowInListSettings", "TRUE")); } // Extend the basic field scheme (everything listed above here) with the specific field type's extra attributes return(fieldInfo.Schema(schema)); }
/// <summary> /// Ensure a field /// </summary> /// <param name="fieldCollection">The field collection</param> /// <param name="fieldInfo">The field info configuration</param> /// <returns>The internal name of the field</returns> public SPField EnsureField(SPFieldCollection fieldCollection, BaseFieldInfo fieldInfo) { SPList parentList = null; bool isListField = TryGetListFromFieldCollection(fieldCollection, out parentList); bool alreadyExistsAsSiteColumn = fieldCollection.Web.Site.RootWeb.Fields.TryGetFieldByStaticName(fieldInfo.InternalName) != null; if (fieldInfo.EnforceUniqueValues) { bool isValidTypeForUniquenessConstraint = fieldInfo is IntegerFieldInfo || fieldInfo is NumberFieldInfo || fieldInfo is CurrencyFieldInfo || fieldInfo is DateTimeFieldInfo || fieldInfo is TextFieldInfo || fieldInfo is UserFieldInfo || fieldInfo is LookupFieldInfo || fieldInfo is TaxonomyFieldInfo; if (!isValidTypeForUniquenessConstraint) { string msg = "Can't set EnforceUniqueValues=TRUE on your field " + fieldInfo.InternalName + " because only the following field types are support uniqueness constraints: " + " Integer, Number, Currency, DateTime, Text (single line), User (not multi), Lookup (not multi) and Taxonomy (not multi)."; throw new NotSupportedException(msg); } } if (isListField && !alreadyExistsAsSiteColumn) { // By convention, we enfore creation of site column before using that field on a list this.InnerEnsureField(fieldCollection.Web.Site.RootWeb.Fields, fieldInfo); } return this.InnerEnsureField(fieldCollection, fieldInfo); }
/// <summary> /// Ensure a field /// </summary> /// <param name="fieldCollection">The field collection</param> /// <param name="fieldInfo">The field info configuration</param> /// <returns>The internal name of the field</returns> public SPField EnsureField(SPFieldCollection fieldCollection, BaseFieldInfo fieldInfo) { SPList parentList = null; bool isListField = TryGetListFromFieldCollection(fieldCollection, out parentList); bool alreadyExistsAsSiteColumn = fieldCollection.Web.Site.RootWeb.Fields.TryGetFieldByStaticName(fieldInfo.InternalName) != null; if (fieldInfo.EnforceUniqueValues) { bool isValidTypeForUniquenessConstraint = fieldInfo is IntegerFieldInfo || fieldInfo is NumberFieldInfo || fieldInfo is CurrencyFieldInfo || fieldInfo is DateTimeFieldInfo || fieldInfo is TextFieldInfo || fieldInfo is UserFieldInfo || fieldInfo is LookupFieldInfo || fieldInfo is TaxonomyFieldInfo; if (!isValidTypeForUniquenessConstraint) { string msg = "Can't set EnforceUniqueValues=TRUE on your field " + fieldInfo.InternalName + " because only the following field types are support uniqueness constraints: " + " Integer, Number, Currency, DateTime, Text (single line), User (not multi), Lookup (not multi) and Taxonomy (not multi)."; throw new NotSupportedException(msg); } } if (isListField && !alreadyExistsAsSiteColumn) { // By convention, we enfore creation of site column before using that field on a list this.InnerEnsureField(fieldCollection.Web.Site.RootWeb.Fields, fieldInfo); } return(this.InnerEnsureField(fieldCollection, fieldInfo)); }
private static void ClearTermStoreMapping(SPFieldCollection fieldCollection, BaseFieldInfo taxonomyFieldInfo) { var taxoField = (TaxonomyField)fieldCollection[taxonomyFieldInfo.Id]; taxoField.AnchorId = Guid.Empty; taxoField.TermSetId = Guid.Empty; taxoField.SspId = Guid.Empty; taxoField.Update(taxonomyFieldInfo.AreChangesPushedToList); }
private void UpdateFieldVisibility(SPField field, BaseFieldInfo fieldInfo) { field.ShowInListSettings = !fieldInfo.IsHiddenInListSettings; field.ShowInDisplayForm = !fieldInfo.IsHiddenInDisplayForm; field.ShowInEditForm = !fieldInfo.IsHiddenInEditForm; field.ShowInNewForm = !fieldInfo.IsHiddenInNewForm; // Apply Hidden here again (even through it's already set through the schema XML), // because otherwise updates to Hidden will not work. if (!field.CanToggleHidden) { bool before = field.Hidden; // Use reflection to get around the CanToggleHidden constraint. Keep in mind that // there may be some unintended consequenced from hiding/showing and previously // shown/hidden field (hence the logged warning). Type type = field.GetType(); MethodInfo mi = type.GetMethod("SetFieldBoolValue", BindingFlags.NonPublic | BindingFlags.Instance); mi.Invoke(field, new object[] { "CanToggleHidden", true }); field.Hidden = fieldInfo.IsHidden; mi.Invoke(field, new object[] { "CanToggleHidden", false }); this.log.Warn( string.Format( CultureInfo.InvariantCulture, "FieldHelper.EnsureField - Forced field (id={0}, name={1}) from Hidden={2} to Hidden={3} even though it should've been impossible because CanToggleHidden=false.", field.Id, field.InternalName, before, fieldInfo.IsHidden)); } else { // No need to use reflection before being able to set the Hidden property field.Hidden = fieldInfo.IsHidden; } }
private void UpdateFieldTypeSpecificProperties(SPFieldCollection parentFieldCollection, SPField field, BaseFieldInfo fieldInfo) { // Set field properties var asTaxonomyFieldInfo = fieldInfo as TaxonomyFieldInfo; var asTaxonomyMultiFieldInfo = fieldInfo as TaxonomyMultiFieldInfo; var asCurrencyFieldInfo = fieldInfo as CurrencyFieldInfo; // Enforce unique values (should work only on list fields) if (fieldInfo.EnforceUniqueValues) { if (parentFieldCollection.List != null) { field.Indexed = true; } field.EnforceUniqueValues = true; } else { field.EnforceUniqueValues = false; } if (asTaxonomyFieldInfo != null) { var taxonomyField = field as TaxonomyField; if (taxonomyField != null) { taxonomyField.CreateValuesInEditForm = asTaxonomyFieldInfo.CreateValuesInEditForm; taxonomyField.Open = asTaxonomyFieldInfo.CreateValuesInEditForm; taxonomyField.IsPathRendered = asTaxonomyFieldInfo.IsPathRendered; field = taxonomyField; // this call will take care of calling Update() on field this.ApplyTaxonomyTermStoreMapping(parentFieldCollection, field, asTaxonomyFieldInfo); } } else if (asTaxonomyMultiFieldInfo != null) { var taxonomyField = field as TaxonomyField; if (taxonomyField != null) { taxonomyField.CreateValuesInEditForm = asTaxonomyMultiFieldInfo.CreateValuesInEditForm; taxonomyField.Open = asTaxonomyMultiFieldInfo.CreateValuesInEditForm; taxonomyField.IsPathRendered = asTaxonomyMultiFieldInfo.IsPathRendered; field = taxonomyField; // this call will take care of calling Update() on field this.ApplyTaxonomyMultiTermStoreMapping(parentFieldCollection, field, asTaxonomyMultiFieldInfo); } } else if (asCurrencyFieldInfo != null) { // gotta set locale here because it doesn't get persisted through schema XML ((SPFieldCurrency)field).CurrencyLocaleId = asCurrencyFieldInfo.LocaleId; } }
private SPField InnerEnsureField(SPFieldCollection fieldCollection, BaseFieldInfo fieldInfo) { SPField field = null; if (fieldInfo.GetType().Name.StartsWith("MinimalFieldInfo", StringComparison.OrdinalIgnoreCase)) { // Ensuring a MinimalFieldInfo from its SchemaXML is impossible since the MinimalFieldInfo object // doesn't hold enough information to completely describe the field metadata. // Instead, we have to re-use the site column and apply it to the list. var existingSiteColumn = fieldCollection.Web.Site.RootWeb.Fields.TryGetFieldByStaticName(fieldInfo.InternalName); if (existingSiteColumn == null) { throw new NotSupportedException( string.Format( CultureInfo.InvariantCulture, "Failed to ensure MinimalFieldInfo for field {0} because the pre-requisite Site Column doesn't exist.", fieldInfo.InternalName)); } SPList parentList = null; if (!TryGetListFromFieldCollection(fieldCollection, out parentList)) { throw new NotSupportedException( string.Format( CultureInfo.InvariantCulture, "Failed to ensure MinimalFieldInfo for field {0}. A MinimalFieldInfo can only be used to ensure a Field on a List's SPFieldCollection, not to re-define an OOTB site column definition.", fieldInfo.InternalName)); } fieldCollection.Add(existingSiteColumn); field = fieldCollection[existingSiteColumn.Id]; } else { // We have a fully-functional/fully-detailed IFieldInfo which should support a conversion to SchemaXML: go ahead and try to add the field. XElement xmlSchemaForField = this.fieldSchemaHelper.SchemaForField(fieldInfo); field = this.fieldSchemaHelper.EnsureFieldFromSchema(fieldCollection, xmlSchemaForField); } // In some cases, the returned field will not match the one we meant to create or ensure. For example, // we may have defined a fieldInfo with an InternalName that clashes with an already existing field. // In such a case, EnsureFieldFromSchema will return us the conflicting/already existing field (not // the one we mean to ensure). if (field.Id == fieldInfo.Id && field.InternalName == fieldInfo.InternalName) { try { var refetchedField = fieldCollection[field.Id]; } catch (ArgumentException) { // in a sneaky edge case, we're dealing with a sub-web's fieldCollection, // and we actually ensured the column on the root web (instead of on the sub-web). fieldCollection = fieldCollection.Web.Site.RootWeb.Fields; } // Set the field visibility this.UpdateFieldVisibility(field, fieldInfo); // Set miscellaneous properties this.UpdateFieldTypeSpecificProperties(fieldCollection, field, fieldInfo); // Tiny bit of ugly reflection here: we assume that all implementations of IFieldInfo will // derive from FieldInfo<T>, which in turn lets us assume a DefaultValue property will always // be there for us to create our FieldValueInfo (which simply needs an untyped object as value). FieldValueInfo defaultValueFieldInfo = new FieldValueInfo(fieldInfo, fieldInfo.GetType().GetProperty("DefaultValue").GetValue(fieldInfo)); this.fieldValueWriter.WriteValueToFieldDefault(fieldCollection, defaultValueFieldInfo); if (!string.IsNullOrEmpty(fieldInfo.DefaultFormula)) { if (!string.IsNullOrEmpty(field.DefaultValue)) { // A default value was already specified, so setting a Formula makes no sense. throw new InvalidOperationException("Failed to ensure field " + fieldInfo.InternalName + " in its entirety because both DefaultFormula and DefaultValue properties were specified. Please only set Formula OR DefaultValue, not both. Also don't forget to clean up the partially created field " + fieldInfo.InternalName + "."); } // Setting the DefaultFormula through the SchemaXML doesn't work, // so let's force it here. field.DefaultFormula = fieldInfo.DefaultFormula; } field.Update(); } return field; }
private static void ClearTermStoreMapping(SPFieldCollection fieldCollection, BaseFieldInfo taxonomyFieldInfo) { var taxoField = (TaxonomyField)fieldCollection[taxonomyFieldInfo.Id]; taxoField.AnchorId = Guid.Empty; taxoField.TermSetId = Guid.Empty; taxoField.SspId = Guid.Empty; taxoField.Update(); }
private void ValidateFieldBasicValues(BaseFieldInfo fieldInfo, SPField field) { Assert.AreEqual(fieldInfo.Id, field.Id); Assert.AreEqual(fieldInfo.InternalName, field.InternalName); Assert.AreEqual(fieldInfo.DisplayNameResourceKey, field.TitleResource.Value); Assert.AreEqual(fieldInfo.DescriptionResourceKey, field.DescriptionResource.Value); Assert.AreEqual(fieldInfo.GroupResourceKey, field.Group); Assert.AreEqual(fieldInfo.EnforceUniqueValues, field.EnforceUniqueValues); Assert.AreEqual(fieldInfo.IsHidden, field.Hidden); Assert.AreEqual(!fieldInfo.IsHiddenInDisplayForm, field.ShowInDisplayForm); Assert.AreEqual(!fieldInfo.IsHiddenInNewForm, field.ShowInNewForm); Assert.AreEqual(!fieldInfo.IsHiddenInEditForm, field.ShowInEditForm); Assert.AreEqual(!fieldInfo.IsHiddenInListSettings, field.ShowInListSettings); Assert.AreEqual(fieldInfo.Required == RequiredType.Required, field.Required); }
private SPField InnerEnsureField(SPFieldCollection fieldCollection, BaseFieldInfo fieldInfo) { SPField field = null; if (fieldInfo.GetType().Name.StartsWith("MinimalFieldInfo", StringComparison.OrdinalIgnoreCase)) { // Ensuring a MinimalFieldInfo from its SchemaXML is impossible since the MinimalFieldInfo object // doesn't hold enough information to completely describe the field metadata. // Instead, we have to re-use the site column and apply it to the list. var existingSiteColumn = fieldCollection.Web.Site.RootWeb.Fields.TryGetFieldByStaticName(fieldInfo.InternalName); if (existingSiteColumn == null) { throw new NotSupportedException( string.Format( CultureInfo.InvariantCulture, "Failed to ensure MinimalFieldInfo for field {0} because the pre-requisite Site Column doesn't exist.", fieldInfo.InternalName)); } SPList parentList = null; if (!TryGetListFromFieldCollection(fieldCollection, out parentList)) { throw new NotSupportedException( string.Format( CultureInfo.InvariantCulture, "Failed to ensure MinimalFieldInfo for field {0}. A MinimalFieldInfo can only be used to ensure a Field on a List's SPFieldCollection, not to re-define an OOTB site column definition.", fieldInfo.InternalName)); } fieldCollection.Add(existingSiteColumn); field = fieldCollection[existingSiteColumn.Id]; } else { // We have a fully-functional/fully-detailed IFieldInfo which should support a conversion to SchemaXML: go ahead and try to add the field. XElement xmlSchemaForField = this.fieldSchemaHelper.SchemaForField(fieldInfo); field = this.fieldSchemaHelper.EnsureFieldFromSchema(fieldCollection, xmlSchemaForField); } // In some cases, the returned field will not match the one we meant to create or ensure. For example, // we may have defined a fieldInfo with an InternalName that clashes with an already existing field. // In such a case, EnsureFieldFromSchema will return us the conflicting/already existing field (not // the one we mean to ensure). if (field.Id == fieldInfo.Id && field.InternalName == fieldInfo.InternalName) { try { var refetchedField = fieldCollection[field.Id]; } catch (ArgumentException) { // in a sneaky edge case, we're dealing with a sub-web's fieldCollection, // and we actually ensured the column on the root web (instead of on the sub-web). fieldCollection = fieldCollection.Web.Site.RootWeb.Fields; } // Set the field visibility this.UpdateFieldVisibility(field, fieldInfo); // Set miscellaneous properties this.UpdateFieldTypeSpecificProperties(fieldCollection, field, fieldInfo); // Tiny bit of ugly reflection here: we assume that all implementations of IFieldInfo will // derive from FieldInfo<T>, which in turn lets us assume a DefaultValue property will always // be there for us to create our FieldValueInfo (which simply needs an untyped object as value). FieldValueInfo defaultValueFieldInfo = new FieldValueInfo(fieldInfo, fieldInfo.GetType().GetProperty("DefaultValue").GetValue(fieldInfo)); this.fieldValueWriter.WriteValueToFieldDefault(fieldCollection, defaultValueFieldInfo); if (!string.IsNullOrEmpty(fieldInfo.DefaultFormula)) { if (!string.IsNullOrEmpty(field.DefaultValue)) { // A default value was already specified, so setting a Formula makes no sense. throw new InvalidOperationException("Failed to ensure field " + fieldInfo.InternalName + " in its entirety because both DefaultFormula and DefaultValue properties were specified. Please only set Formula OR DefaultValue, not both. Also don't forget to clean up the partially created field " + fieldInfo.InternalName + "."); } // Setting the DefaultFormula through the SchemaXML doesn't work, // so let's force it here. field.DefaultFormula = fieldInfo.DefaultFormula; } // Set the JavaScript custom rendering file URL if (!string.IsNullOrEmpty(fieldInfo.JsLink)) { field.JSLink = fieldInfo.JsLink; } field.Update(fieldInfo.AreChangesPushedToList); } return(field); }
/// <summary> /// Generates the Field XML for a site column definition /// </summary> /// <param name="fieldInfo">The field definition for which we want to print out the full XML schema</param> /// <returns>The XML schema of the field</returns> public XElement SchemaForField(BaseFieldInfo fieldInfo) { var schema = new XElement( "Field", new XAttribute("Name", fieldInfo.InternalName), new XAttribute("Type", fieldInfo.FieldType), new XAttribute("ID", "{" + fieldInfo.Id + "}"), new XAttribute("StaticName", fieldInfo.InternalName), new XAttribute("DisplayName", this.resourceLocator.GetResourceString(fieldInfo.ResourceFileName, fieldInfo.DisplayNameResourceKey)), new XAttribute("Description", this.resourceLocator.GetResourceString(fieldInfo.ResourceFileName, fieldInfo.DescriptionResourceKey)), new XAttribute("Group", this.resourceLocator.GetResourceString(fieldInfo.ResourceFileName, fieldInfo.GroupResourceKey))); // Check the Required type if (fieldInfo.Required == RequiredType.Required) { schema.Add(new XAttribute("Required", "TRUE")); } if (fieldInfo.Required == RequiredType.NotRequired) { schema.Add(new XAttribute("Required", "FALSE")); } // Hidden state if (fieldInfo.IsHidden) { schema.Add(new XAttribute("Hidden", "TRUE")); } // Show in Display Form if (fieldInfo.IsHiddenInDisplayForm) { schema.Add(new XAttribute("ShowInDisplayForm", "FALSE")); } // Show in Edit Form if (fieldInfo.IsHiddenInEditForm) { schema.Add(new XAttribute("ShowInEditForm", "FALSE")); } // Show in new Form if (fieldInfo.IsHiddenInNewForm) { schema.Add(new XAttribute("ShowInNewForm", "FALSE")); } // Show in List settings if (fieldInfo.IsHiddenInListSettings) { schema.Add(new XAttribute("ShowInListSettings", "FALSE")); } else { schema.Add(new XAttribute("ShowInListSettings", "TRUE")); } // Extend the basic field scheme (everything listed above here) with the specific field type's extra attributes return fieldInfo.Schema(schema); }
/// <summary> /// Initializes a new instance of the <see cref="FieldValueInfo"/> class. /// </summary> /// <param name="fieldInfo">The field information for which the value will be set to.</param> /// <param name="value">The value to set to the field. The type of the object must be the same as the FieldInfo AssociatedValueType.</param> public FieldValueInfo(BaseFieldInfo fieldInfo, object value) { this.FieldInfo = fieldInfo; this.Value = value; }