Monday, August 12, 2013

Exception setting „Hidden” Cannot change Hidden attribute for this field”

Requirements:
Requirements was to remove the Taxonomy fieldParent Companyfrom the Sharepoint List  as this field is not used by anyone.
Issue:
Issue with theParent Companyfield deleting with PowerShell script. After the script run the following error message has appeared. Exception settingHiddenCannot change Hidden attribute for this field
Investigation:
This is an internal issue in SharePoint2010.
The common issue description can be found here: http://blogs.msdn.com/b/spblog/archive/2013/04/27/sps2010-field-cannot-be-made-again-visible-if-defined-to-be-hidden-using-visual-studio-2010.aspx .
During development the fieldParent Companywas created usisng xml definition in Visual Studio 2010 and a field attributeHiddenwas set to valueTrue” (true if the field is hidden; otherwisefalse.)
<Field
       ID="{747FC1CF-FCED-44EB-B895-568E9F423174}"
        Name="ALLegalCompanyTaxHTField1"
        StaticName="ALLegalCompanyTaxHTField1"
        Type="Note"
        Overwrite="TRUE"
        RowOrdinal="0"
        DisplayName="$Resources:IntranetGroupDirectory,Fields_ParentCompany_DisplayName;"
        Group="$Resources:IntranetGroupDirectory,GroupDirectory_CT_Group;"
        Description="$Resources:IntranetGroupDirectory,Fields_ParentCompany_Description;"
        Hidden ="TRUE">
  </Field>
An taxonomy field consists of  two fields (example: „Parent Companycan be seen on screenhot)
TheParent Companyis a taxonomy field and consists of two fields definition ALLegalCompany and ALLegalCompanyTaxHTField1
<Field
        ID="{B5FE2B9E-CDF9-4B4A-B34C-85650481A280}"
        Name="ALLegalCompany"
        StaticName="ALLegalCompany"
        Type="TaxonomyFieldType"
        ShowField="Term1033"
        Overwrite="TRUE"
        Mult="TRUE"
        DisplayName="$Resources:IntranetGroupDirectory,Fields_ParentCompany_DisplayName;"
        Group="$Resources:IntranetGroupDirectory,GroupDirectory_CT_Group;"
        Description="$Resources:IntranetGroupDirectory,Fields_ParentCompany_Description;"
        Hidden ="FALSE">
</Field>
The field ALLegalCompany has Hidden proeprty set value to False.
The field ALLegalCompanyTaxHTField1 has propertyHiddenset to True that caused the difficulties to delete this field.
Fields in SharePoint can be added using xml definition via Visual Studio, but cannot be delete that way, therefore the Powershell commands must be used to delete fields from Lists or Content Type. But the fieldParent Comapnycannot be deleted that’s way using scrips, because fields should be visible and property Hidden is set to false. Property Hidden cannot be set to false, because this property depends (relies) on other property called CanToggleHidden and it’s value should be set to True. „CanToggleHiddenproperty is Read-only and  and it’s value cannot be change directly, because there is no setter method (this is a SharePoint property that stored in native assemly (SPField) and was developed that way, the reason of that fact is unknown).
To be possible to change property Hidden to false, the property CanToggleHidden value should be set to True in a field definition, the way like in this example below (but in this case the property is absent at all in the field definition).
<Field
        ID="{747FC1CF-FCED-44EB-B895-568E9F423174}"
        Name="ALLegalCompanyTaxHTField1"
        StaticName="ALLegalCompanyTaxHTField1"
        Type="Note"
        Overwrite="TRUE"
        RowOrdinal="0"
        DisplayName="$Resources:IntranetGroupDirectory,Fields_ParentCompany_DisplayName;"
        Group="$Resources:IntranetGroupDirectory,GroupDirectory_CT_Group;"
        Description="$Resources:IntranetGroupDirectory,Fields_ParentCompany_Description;"
        Hidden ="TRUE"
   CanToggleHidden ="TRUE">
  </Field>
By default CanToggleHidden is return false as it is not presented in the definition. Adding the property and deploy solution don’t change the field defintion.
If we have a look in code at the Hidden property setter in assembly Microsoft.SharePoint.SPField  it also sets „CanToggleHiddenproperty to true, but cannot be reached because it is value by default is false and throw the error message shown in the picture above Exception settingHiddenCannot change Hidden attribute for this field.
this.SetFieldBoolValue("CanToggleHidden", true)
[ClientCallable]
    public bool Hidden
    {
      get
      {
        if (this.HasExternalDataSource)
        {
          return SPExternalList.IsFieldHidden(this);
        }
        return this.GetFieldBoolValue("Hidden", 4);
      }
      [ClientCallableExceptionConstraint(FixedId="1", ErrorCode=-2146232832, Condition="Thrown when attempting to set Hidden property for a field that does not allow this property to be toggled.", ErrorType=typeof(SPException))]
      set
     {
        if (!this.CanToggleHidden)
        {
          throw new SPException(SPResource.GetString("HiddenAttributeUpdateNotAllowed", new object[0]));
        }
        this.SetFieldBoolValue("Hidden", value);
        this.SetFieldBoolValue("CanToggleHidden", true);
      }
    }

Solution:
Solution was found to use reflection to change propertyCanToggleHiddenvalue to True, cahnge Hidden property to false and delete the field from the List via PowerShell

PowerShell example:

$web = Get-SPWeb  "http://sharepoint/
$listLegComp = $web.Lists["YourList"]
$pcFieldTax = $listLegComp.Fields.GetFieldByInternalName("ALLegalCompanyTaxHTField1")
$pcField = $listLegComp.Fields.GetFieldByInternalName("ALLegalCompany")
if(!$pcFieldTax.CanToggleHidden)
{
   $bindingFlags = [Reflection.BindingFlags] "NonPublic,Instance"
   [System.Type] $type = $pcFieldTax.GetType()
   [Reflection.MethodInfo] $mdInfo = $type.GetMethod("SetFieldBoolValue",$bindingFlags)
   $object = [System.Object] @("CanToggleHidden",$true)
   $mdInfo.Invoke($pcFieldTax,$object)
   $pcFieldTax.Hidden = $false
   $pcFieldTax.AllowDeletion = $true
   $pcFieldTax.Update()
     
}
if(!$pcField.CanToggleHidden)
{
   $bindingFlags = [Reflection.BindingFlags] "NonPublic,Instance"
   [System.Type] $type = $pcField.GetType()
   [Reflection.MethodInfo] $mdInfo = $type.GetMethod("SetFieldBoolValue",$bindingFlags)
   $object = [System.Object] @("CanToggleHidden",$true)
   $mdInfo.Invoke($pcField,$object)
   $pcField.Hidden = $false
   $pcField.AllowDeletion = $true
   $pcField.Update() 
}

$pcFieldTax.Delete()
$pcField.Delete()
$listLegComp.Update()
$web.Dispose()

6 comments:

  1. Saved a lot of time and hard work...Thanks a lot :)

    --
    Kalpana

    ReplyDelete
  2. This was a perfect solution - helped me a lot

    ReplyDelete
    Replies
    1. I am glad that my article helped you. Thank you for you comment.

      Delete
  3. Thanks, great time saver
    Just for the record there is a typo in your first condition :

    $pcField = $listLegComp.Fields.GetFieldByInternalName("ALLegalCompany")
    if(!$pcField.CanToggleHidden)

    Should be

    $pcField = $listLegComp.Fields.GetFieldByInternalName("ALLegalCompany")
    if(!$pcFieldTax .CanToggleHidden)
    {

    G2x.

    ReplyDelete
    Replies
    1. Thank you for you comment. Glad it helped you. I have corrected the type you have mentioned, thx, I appreciate it.

      Delete