понедельник, 22 апреля 2013 г.

Атрибуты ViewFields

С первого взгляда, ViewFields - это попросту список полей, которые отображаются в том или ином представлении списка. В C# API этот список полей представлен классом SPViewFieldCollection, который является по сути коллекцией строк, представляющих собой InternalName полей, отображаемых представлением.

Немногие знают, что каждое поле внутри ViewFields (элементы FieldRef) еще может иметь атрибуты, которые определяют, как именно это поле включается в представление списка. Большая часть этих атрибутов присутствует у исходных SPField (однако не все атрибуты SPField переопределяемы!), и установка их в FieldRef позволяет просто переопределить (override) настройки поля в рамках конкретного представления.

Меню элемента


Пожалуй, одни из самых известных и используемых атрибутов элементов ViewFields - это LinkToItem и ListItemMenu. Они позволяют "подцепить" соответственно ссылку на Display форму элемента и меню элемента на произвольное поле списка - без всяких там XSLT преобразований. Нередко эти атрибуты используются, например, в библиотеках документов, где вместо имени файла предпочтительнее отображать заголовок документа (Title) - и соответственно, меню элемента должно быть перенесено на заголовок.

<FieldRef Name="MyField" LinkToItem="TRUE" ListItemMenu="TRUE" />

В SharePoint 2013, к слову, добавился похожий атрибут "CalloutMenu", который позволяет отобразить более современное меню элемента вида "Callout".

Фильтрация и сортировка


Установка атрибутов Filterable и Sortable в FALSE поможет запрещать фильтрацию и сортировку выбранных полей в пределах вашего представления. Дополнительно, можно указать сообщение, которое будет отображаться, когда фильтрация недоступна (атрибут FilterDisableMessage).

Когда это требуется?

  1. Например, вы выносите фильтр по некоторому полю в отдельную панель наверху представления, и улучшаете этот фильтр, делаете его более "user friendly". Скажем, вместо фильтрации по конкретной дате, вы предлагаете пользователю выбрать месяц/год или даже лучше - выбрать конкретный диапазон дат. В этом случае фильтр в заголовке колонки становится ненужным, и почему бы его не запретить.
  2. В некоторых полях фильтрация просто выглядит глупо (яркий пример - поле "Title").
  3. Когда вы используете в запросе представления (тэг <Query>) параметры (значения из ParameterBindings), фильтры SharePoint ломаются, т.е. не выдают вариантов для фильтрации, как будто в колонке совсем нет данных. В этом случае я предпочитаю явно запрещать фильтрацию и определять сообщение об ошибке для всех полей, что-нибудь типа "В этом представлении фильтрация невозможна"...

Explicit


Исключительно полезный атрибут - Explicit. Значение его трудно переоценить, особенно если вы работаете с какими-то коробочными решениями или с большими проектами, где много пользователей с разными уровнями привилегий. Но даже и на маленьких проектах, этот атрибут часто важен!

Explicit делает две вещи:
  1. Скрывает поле из представления. Т.е. данные для поля будут запрашиваться и поступать в XSLT преобразование, но отображаться соответствующие поля не будут, пока вы их сами не отобразите.
  2. Не дает пользователю удалить поле из представления!!

Те люди, которые используют свойство Sealed у SPField, меня поймут! :)

Для остальных поясню: кастомизированное представление - вещь довольно хрупкая. Удалили критически важное поле из представления - представление разъехалось или начало глючить. А клиенты, они такие - любят удалять "ненужное" :) Нередко бывает, что ошибки замечают не сразу. Проходит несколько дней, в конце концов обнаруживают ошибку, но никто уже не помнит что он там когда-то давно что-то "чистил". В итоге, клиент с черной тучкой над головой звонит в вашу техподдержку....

SharePoint итак далек от идеала, и дополнительный негатив для клиента создавать на пустом месте безусловно не стоит, даже если вам кажется что он не оправдан. Ошибку можно обрабатывать в коде, но это неправильный подход, и он всегда более дорогой. Идеальный вариант - просто запрещать удалять поля из представления. А Explicit - это единственный предусмотренный и правильный способ это делать.

SharePoint 2013


В SharePoint 2013, помимо уже упоминавшегося выше CalloutMenu, к ViewFields добавилось немало новых интересных атрибутов. В частности, это атрибуты для управления отображением полей типа "Пользователь": WithPicture, PictureSize, PictureOnly, и некоторые другие.

Например, добавление WithPicture="TRUE" к полю "Created By" (InternalName="Author") выдает вот такой результат:

А вот такой FieldRef:

<FieldRef Name="Author" PictureSize="Size_36px" PictureOnly="TRUE" />

Будет отображен следующим образом:
Таким образом, можно изменять отображение одного и того же поля в зависимости от представления. Это нередко пригождается на практике, чтобы "зафиксировать" режим отображения поля для кастомизированного представления, чтобы вне зависимости от того что пользователь может поменять некоторые настройки для поля через веб-интерфейс, это поле отображалось бы в нашем представлении именно так, как нужно.

Еще один атрибут, специфичный для SP2013, о котором хотелось бы упомянуть - это AllowGridEditing. Он позволяет сделать ту или иную колонку нередактируемой в режиме Grid в рамках данного представления. Выглядит полезно, но будьте осторожны: ограничение редактирования такого рода запретами ненадежно, всегда можно будет изменить это поле куском JS через Client Object Model. О том, как правильно управлять разрешениями и доступом в SharePoint, у меня есть отдельная статья.

Еще раз напомню: все эти атрибуты как правило доступны в виде свойств объекта SPField, т.е. их можно задавать и на уровне поля, для всех представлений сразу.

Другие атрибуты


Есть для элементов ViewFields/FieldRef и другие атрибуты. Например, атрибуты Len и MoreText, нужные для обрезания текста...

Еще один атрибут, тоже иногда пригождающийся - это AutoHyperLink. Он позволяет внутри обычного текстового поля разрешить абсолютные URL-ссылки. Результат выглядит примерно так:


Иными словами, ссылки, помещенные внутрь текста, становятся кликабельными. Повторюсь, работает это только для обычных текстовых полей.

Как задать атрибуты ViewFields программно?


Как я уже упоминал выше, через SPView.ViewFields задать эти атрибуты нельзя. Что же делать?

Очевидно, решение - это попробовать как-то передать в SPView кусок View XML. К сожалению, напрашивающийся для этого метод SetViewXml попросту не работает - проглатывает любой поданный ему XML, но после Update изменения не сохраняются в БД.

Впрочем, если тщательно пошарить в MSDN, вы обнаружите, что конструктор SPView принимает XmlDocument, что практически то что нужно! Однако, метод Update на созданном таким образом SPView, как ни странно, не работает!... Решение этой проблемы можно найти там же в MSDN, в секции Remarks:

Use the Clone method on the constructed view object to add the view to collection of views for the list.

Кто бы мог подумать! Создаем SPView используя конструктор, а потом его клонируем, и вот тогда уже можно сохранять. Система нипель, блин :)

Вот вам рабочий код:

var doc = new XmlDocument();
doc.LoadXml("<View ...>...</View>"); // or load from file: doc.Load("myview.xml");
var tempView = new SPView(list, doc);
var view = tempView.Clone("My view", 30, true, false);
view.Update();

Заключение

Создание кастомизированного представления списка - это частая потребность. Поэтому важно уметь управлять представлением и его полями в полной мере. Надеюсь, описанные мной здесь, по большей части малоизвестные атрибуты элементов ViewFields помогут сделать ваши представления лучше. Удачи!

4 комментария:

  1. Андрей был бы Вам признателен если бы Вы указали ссылку на MSDN, а то найти не могу описание FieldRef Element (View) для 10 или 13го.

    ОтветитьУдалить
    Ответы
    1. Александр, документация по FieldRef на MSDN очень путанная. Напомню, FieldRef - это в некотором роде "универсальный" элемент, который много где используется. Например, он используется повсеместно внутри тэга Query, причем внутри этого тега есть как минимум 3 варианта FieldRef - все с разными атрибутами: Query/GroupBy/FieldRef, Query/OrderBy/FieldRef, Query/Where/FieldRef. Еще FieldRef используется в ContentType, View/Aggregations, View/ProjectedFields и т.п.

      Элемент FieldRef сходен во всех этих случаях тем, что имеет атрибуты Name и ID, и также логически он всегда обозначает ссылку на SPField. Но вот отстальные атрибуты (кроме Name и ID) могут очень сильно отличаться.

      В этой статье я говорю конкретно об атрибутах View/ViewFields/FieldRef. По спецификации, для View/FieldRef есть только 2 атрибута: Name и Explicit. Но это, естественно, не соответствует действительности...

      Так что можно считать все атрибуты выше по большому счету не документированными.

      Удалить
  2. В PS и без клона обошлось, через SetViewXml(...) и Update()

    ОтветитьУдалить
    Ответы
    1. Не работает SetViewXml, и судя по рефлектора, и не может. Проверял много раз сам и в интернетах тоже люди много про это пишут.

      А не SP2013 случайно? В 2013 я эту штуку не проверял еще, вдруг исправили :)

      Удалить

Внимание! Реклама и прочий спам будут беспощадно удаляться.