1

I need to programmatically retrieve the columns in a Sharepoint document library, in order to set file properties externally to Sharepoint.

I've found that setting the metadata property is not hard as long as you already know the name of the column, which I cannot expect users to input themselves.

As it does not seem possible to do this through the Sharepoint Web Services I have created my own custom web service so I have access to the Client Object Model.

List Custom Columns

Using this code I am able to retrieve the custom columns I have created, however I am not able to distinguish between the ones editable in the item properties section (picture above) and those which aren't.

SPList list = web.Lists[specificList];
foreach (SPField field in list.Fields)
{
    if (!field.Hidden)
    {
        var title = field.Title;
        var description = field.Description;
        var parentList = field.ParentList;

        var references = field.FieldReferences; // contains names of fields referenced in computed fields

        if (references != null)
        {
            foreach (string reference in references)
            {
                var test = parentList.Fields.GetField(reference);
            }
        }
    }
}

I get extra properties such as:

  • Copy Source
  • Content Type
  • Checked Out To
  • Checked In Comment
  • Type
  • File
  • Size
  • Edit
  • Version
  • Source Version
  • Source Name

I have also tried retrieving the column fields from the SPFolder item, but again this returns many extra properties and is even less filterable.

foreach (SPListItem folderItem in list.Folders)
{
    SPFolder folder = folderItem.Folder;
    System.Collections.Hashtable oHashtable = folder.Properties;
    System.Collections.ICollection collKeys = oHashtable.Keys;

    foreach (var key in collKeys)
    {
        string keyName = key.ToString();
    }
}

Is there a standard way to retrieve the column fields I need? Or will I have to manually exclude the defaults ones such as "Checked out to"?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Amicable
  • 3,115
  • 3
  • 49
  • 77

2 Answers2

1

First you have to know which form you are viewing. Is it the EditForm or NewForm?

You can filter the columns visible on a specific form by getting the fields of the ContentType and then check if they are getting displayed on the NewForm (or whatever form):

SPList list = web.Lists[specificList];
var contentType = list.ContentTypes[0]; // Select first contenttype. Change this if you need a different contentType
foreach (SPField field in contentType.Fields)
{
    if (!field.Hidden 
        && (field.ShowInEditForm == null
            || !field.ShowInEditForm.Value)) // Replace ShowInEditForm with the form you need
    {
        var title = field.Title;
        var description = field.Description;
        var parentList = field.ParentList;

        var references = field.FieldReferences; // contains names of fields referenced in computed fields

        if (references != null)
        {
            foreach (string reference in references)
            {
                var test = parentList.Fields.GetField(reference);
            }
        }
    }
}
RononDex
  • 4,143
  • 22
  • 39
  • Looks good, need to do some further testing but this looks like the answer, and it also seems possible to exclude specific contentTypes using the `SPBuiltInContentTypeId` enum. `ShowInEditForm` does need a null check though. – Amicable Jan 06 '14 at 14:55
  • The only field that returns true for any of the `ShowIn"X"` properties (Aside from `ShowInVersionHistory`) is "Title" which appears in `ShowInEditForm`. So this does not appear to be a solution. – Amicable Jan 06 '14 at 15:40
  • Try also loading those that have null. Only remove those that have value of false. Null usually means that it wasn't specified by the field definition if it should get displayed or not and it then inherits the value from its parent field. – RononDex Jan 06 '14 at 15:41
  • I do still get "Content Type" and the "Document Created/Modified by" fields by doing that but I think at this point I can just exclude those few from the results. – Amicable Jan 06 '14 at 15:53
  • 1
    @Amicable actually this is normal, as those fields are being displayed on any form by default. Just not as a "normal" field, but instead as gray text at the bottom of the form. – RononDex Jan 06 '14 at 16:01
0

I think the best way to go is to get the fields from the content type and not the list itself. That way you'll get only the fields visible in the form.

var list = web.Lists[specificList];
var contentType = list.ContentTypes["Document"];
foreach (SPField field in contentType.Fields)
{
    if(!field.Reorderable || contentType.FieldLinks[field.Id].Hidden)
    { 
        continue;
    }

    //Process fields
}

You may ask "Why Reordable=false?". Well, generally custom fields do not set this property so it is a nice way to filter them.

Also I didn't invent this code. This code is taken from code behind class of SharePoint standard content type fields reorder page (using reflection).

Yevgeniy.Chernobrivets
  • 3,194
  • 2
  • 12
  • 14
  • 1
    I gave -1 because using `contentType.FieldLinks[field.Id].Hidden` will only return true, if the field is set to hidden on contenttype level, and not on field definition level. That way you won't exclude 99% of the hidden fields. Furthermore you are missing a `;` at the end of your 2nd line. – RononDex Jan 06 '14 at 14:37
  • Also using `!field.Reorderable` is a really bad practise in this case. I shouldn't have to explain why. Further you said this is not your code, giving me the impression that you have no clue what it is doing or how the code exactly works which only gets more confirmed by your lack of understanding what the difference is between `contentType.FieldLinks` and `contentType.Fields`. You can prove me wrong – RononDex Jan 06 '14 at 15:10
  • I won't go with you in any discussions. If you do not understand this code don't use it. This code works for document libraries(it may not work for lists in all cases though). contentType.FieldLinks[field.Id].Hidden attribute is inherited from SPField.Hidden by default. – Yevgeniy.Chernobrivets Jan 06 '14 at 15:43
  • Also please explain why using !field.Reorderable is a bad practice? Or maybe you do not know why? – Yevgeniy.Chernobrivets Jan 06 '14 at 15:44
  • I thought you don't want to go into discussions? !field.Reorderable is a bad practise because if the user defines it's column as non reordable (for example a description field), it will exclude his custom field which he wants in his collection. – RononDex Jan 06 '14 at 15:45
  • ***"contentType.FieldLinks[field.Id].Hidden attribute is inherited from SPField.Hidden by default"*** No it does not. If the user defines the field as hidden inside the contenttype definition it will be different from spfield.hidden. FieldLink.Hidden holds the contettype definition and not the list / web definition. Therefor it is null in 99% of all cases – RononDex Jan 06 '14 at 15:50
  • 1
    Hm, maybe you right in some moments. But to check SPField.Hidden won't be enough because if you enable content type editing contentType.FieldLinks[field.Id].Hidden will be used instead (and field can be made visible even if it is not visible in field definition). – Yevgeniy.Chernobrivets Jan 06 '14 at 15:55
  • Yes thats true. But as he is using a simple list that shouldn't be a problem here. Coding a function that displays the exact same fields as on editform in all cases would consume much more lines of codes and is a overkill in much cases in my opinion. – RononDex Jan 06 '14 at 15:56
  • Why you define description field as non reordable? End user should be able to put it anywhere on the form. – Yevgeniy.Chernobrivets Jan 06 '14 at 15:56
  • I thought reordable is for defining wether it cant be ordered in the list view. My bad then. EDIT: Removed -1 – RononDex Jan 06 '14 at 15:57
  • If he has simple document library then my code will also work because he has no custom content type definition and it has only default "Document" content type which inherits all hidden attributes. – Yevgeniy.Chernobrivets Jan 06 '14 at 16:01