пятница, 24 июня 2011 г.

Метаданные для SPField

У объекта SPField есть два полезных метода: GetCustomProperty и SetCustomProperty. Но к сожалению, использовать их в качестве обычного PropertyBag очень сложно:
  1. Свойства эти можно использовать только для Custom Field Type'ов, прописывая их названия и типы в схеме типа поля
  2. Вдобавок, нужно еще изменять схему экземпляра поля (SPField.Schema), добавляя туда атрибут Customization. Автоматически это почему-то не делается :(
Естественно, динамически добавлять свойства к уже существующим полям с помощью этих методов никак не получится. Однако, решения есть, и они известны. Дело в том, что схема поля (SPField.Schema) позволяет использовать произвольные атрибуты для элемента Field.

Обычно, для того, чтобы их задействовать, используют private методы класса SPField: SetFieldAttributeValue и GetFieldAttributeValue. Но в этом случае, естественно, используется Reflection, который запрещен в Office365. И вообще, Reflection - это хак, а любые хаки желательно обходить стороной.

Поэтому, я написал собственное решение, которое парзит XML и меняет свойство FieldSchema самостоятельно. Решение получилось довольно простым, и я всё чаще и чаще использую этот самодельный PropertyBag для хранения разных дополнительных атрибутов полей.

Код (не забудьте подключить пространство имен System.Xml.Linq):

  private const string nameSpace = "my";

  /// <summary>
  /// Прикрепляем метаданные к колонке списка. Эти метаданные будут храниться
  /// в схеме поля.
  /// </summary>
  /// <param name="field">Колонка (SPField), к которой следует добавить метаданные</param>
  /// <param name="key">Название поля метаданных</param>
  /// <param name="value">Значение поля метаданных</param>
  public void SetFieldMetaData(SPField field, string key, string value)
  {
   var fieldSchema = XDocument.Parse(field.SchemaXml);
   var tabAttribute = fieldSchema.Element("Field").Attribute(XNamespace.Get(nameSpace) + key);
   if (tabAttribute == null)
    fieldSchema.Element("Field").Add(new XAttribute(XNamespace.Get(nameSpace) + key, value));
   else
    tabAttribute.Value = value;

   field.SchemaXml = fieldSchema.ToString();
   field.Update();
  }

  /// <summary>
  /// Получаем метаданные из колонки.
  /// </summary>
  /// <param name="field">Колонка, из которой считываются метаданные</param>
  /// <param name="key">Название поля метаданных</param>
  /// <returns>Возвращает значение поля метаданных для колонки, или null, если поле метаданных с указанным именем не было ранее присоединено к этой колонке.</returns>
  public string GetFieldMetaData(SPField field, string key)
  {
   var fieldSchema = XDocument.Parse(field.SchemaXml);
   var tabAttribute = fieldSchema.Element("Field").Attribute(XNamespace.Get(nameSpace) + key);
   if (tabAttribute == null)
    return null;
   else
    return tabAttribute.Value;
  }

вторник, 21 июня 2011 г.

SharePoint Conference Russia 2011: краткий отчет

Вчера выступал на SharePoint Conference Russia 2011. Это моя первая конференция, первое серьезное выступление, и одновременно, как это ни смешно, вообще первая девелоперская конференция, посещенная мной лично.



Неудивительно, что впечатлений привез целый вагон (о да, я ездил в Москву на поезде, ха-ха!). А также - опыта, наблюдений, и новых знакомств. Но, обо всём по порядку.

среда, 15 июня 2011 г.

Как правильно изменять внешний вид List Form в SharePoint

Всё в SharePoint'е можно делать разными способами. Но в последнее время, очень хочется делать правильно...

На этот раз, мне потребовалось внести изменения на формы стандартного SharePoint'овского списка. Таких форм существует три вида, и вы все их прекрасно знаете:
  1. DisplayForm - форма отображения элемента списка
  2. EditForm - форма изменения элемента списка
  3. NewForm - форма создания нового элемента списка
Из-за большого количества полей в одном из наших списков, мне захотелось разнести эти поля по вкладкам. Причем, захотелось также следующее:
  1. Чтобы сохранилась возможность добавлять новые поля в список
  2. Чтобы можно было перемещать поля из одной вкладки в другую, и менять порядок их следования
  3. Чтобы поля рендерились стандартными средствами 
Для того, чтобы определить принадлежность полей к вкладкам, я раскопал способ добавления пользовательских данных в SPField, и создал симпатичный jquery-интерфейс для того, чтобы этим мог заниматься пользователь. Но дальше дело, неожиданно, застопорилось: оказалось, что народ повсеместно пользуется для подобных целей грязными js-хаками, а такой способ мне категорически не подошел!

И вот, после долгих исследований и поиска в интернетах, мне-таки удалось понять, как же это делается правильно, и воплотить в жизнь вот такую вот красивую форму:



Как видите, часть полей (ФИО и фотография) здесь рендерятся по-особому. Остальные поля рендерятся обычным образом, но разбиваются на вкладки (пользователь может менять порядок полей и принадлежность полей разным вкладкам).

В общем, функционал на мой взгляд, весьма интересный, и в этом посте я расскажу подход к подобным изменениям.

SharePoint: что такое хорошо, и что такое плохо

Всё-таки полезно иногда, когда у тебя вырезают всякий мусор из тела :) После аппендицита, в мозгах словно перещелкнуло: довольно серьезно изменил манеру программирования под SharePoint.

Теперь, я гораздо больше времени трачу на поиск решения. На воплощение - как правило, примерно столько же, сколько раньше. Но зато, на порядок меньше времени - на поддержку созданного решения. И решение получается значительно качественнее.

Как показывает опыт последних месяцев, если тщательно искать, всегда найдется какая-нибудь лазейка, которая позволит более тесно сынтегрироваться с SharePoint, и за счет этого, решение обретет большую гибкость.

Банальный пример: вам требуется как-то по-своему отобразить список. 9 из 10 просто сядут и напишут веб-часть, которая забирает данные из списка и их отображает. И потеряют гигантское количество возможностей, которые они могли бы поиметь, если бы не поленились разобраться с возможностями XsltListViewWebPart.

К примеру, я недавно создал XSL-преобразование, которое меняет отображение одного из стандартных списков. При этом, не только сохранились те стандартные возможности, которые мне были нужны, как например сортировка и фильтрация, но также в качестве неожиданного бонуса, обнаружилась масса других.

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



Это решение поведенчески полностью соответствует обычным представлениям списков: к примеру, можно выделять одну или несколько записей; работают контекстные вкладки Ribbon'а, и т.д.

И еще, как видите, здесь поля могут быть различных типов: E-mail, ссылка, телефон, мобильный телефон. Дак вот, я добился, чтобы при добавлении пользователями портала в представление новых полей, поля эти естественным образом отображаются, и для них можно даже задать тип и отобразить в правой колонке с соответствующей иконкой. Впрочем, это тема для отдельного поста.

Мораль: не ленитесь изучать SharePoint, интегрируйтесь глубже. Оно того стоит!