SPFieldIterator наше все или как изменить внешний вид List Form в SharePoint

Если вы уже сталкивались с задачами кастомизацией видимости полей в элементе или задачами связанными с расширением формы элемента, то вы наверное уже заходили на блоги именитых в Рунете блоггеров, которые публиковали подобного рода статьи. И во многих идет перевес в сторону использования SPD (в простонародье SharePointDesigner ).
Хочу немного поделиться своими впечатлениями по работе с данной кастомизацией и покажу небольшой пример.




Для начала немного из теории


Шаблон по которому рисуются формы списков находится в файле DefaultTemplates.ascx (папка CONTROLTEMPLATES) и называется ListForm (Листинг 1).

<SharePoint:RenderingTemplate id="ListForm" runat="server">
    <Template>
        <span id='part1'>
            <SharePoint:InformationBar runat="server"/>
            <div id="listFormToolBarTop">
            <wssuc:ToolBar CssClass="ms-formtoolbar" id="toolBarTbltop" RightButtonSeparator="&#160;" runat="server">
                    <Template_RightButtons>
                        <SharePoint:NextPageButton runat="server"/>
                        <SharePoint:SaveButton runat="server"/>
                        <SharePoint:GoBackButton runat="server"/>
                    </Template_RightButtons>
            </wssuc:ToolBar>
            </div>
            <SharePoint:FormToolBar runat="server"/>
            <SharePoint:ItemValidationFailedMessage runat="server"/>
            <table class="ms-formtable" style="margin-top: 8px;" border="0" cellpadding="0" cellspacing="0" width="100%">
            <SharePoint:ChangeContentType runat="server"/>
            <SharePoint:FolderFormFields runat="server"/>
            <SharePoint:ListFieldIterator runat="server"/>
            <SharePoint:ApprovalStatus runat="server"/>
            <SharePoint:FormComponent TemplateName="AttachmentRows" runat="server"/>
            </table>
            <table cellpadding="0" cellspacing="0" width="100%"><tr><td class="ms-formline"><img src="/_layouts/images/blank.gif" width='1' height='1' alt="" /></td></tr></table>
            <table cellpadding="0" cellspacing="0" width="100%" style="padding-top: 7px"><tr><td width="100%">
            <SharePoint:ItemHiddenVersion runat="server"/>
            <SharePoint:ParentInformationField runat="server"/>
            <SharePoint:InitContentType runat="server"/>
            <wssuc:ToolBar CssClass="ms-formtoolbar" id="toolBarTbl" RightButtonSeparator="&#160;" runat="server">
                    <Template_Buttons>
                        <SharePoint:CreatedModifiedInfo runat="server"/>
                    </Template_Buttons>
                    <Template_RightButtons>
                        <SharePoint:SaveButton runat="server"/>
                        <SharePoint:GoBackButton runat="server"/>
                    </Template_RightButtons>
            </wssuc:ToolBar>
            </td></tr></table>
        </span>
        <SharePoint:AttachmentUpload runat="server"/>
    </Template>
</SharePoint:RenderingTemplate>

Листинг 1. Шаблон по которому рисуются формы списков — ListForm

Контрол 
<SharePoint:ListFieldIterator runat=«server»/>
отвечает за вывод полей. Идея заключается в том, что бы сделать свой ListFieldIterator и подключить его для нужных списков.

Можно сделать несколько ListFieldIterator-оров для разных списков, можно даже для каждой формы (NewForm.aspx, DispForm.aspx, EditForm.aspx) одного и того же списка назначить свой итератор.

Делаем свой итератор

1. Сделать наследника ListFieldIterator — Листинг 2.

public class MyFieldIterator : ListFieldIterator
{
    protected override void CreateChildControls()
    {
        // массивы названий полей можно получать динамически
        // здесь, для примера, они прохардкожены

        var readOnlyFieldsInternalNames = new string[] { "Title", "Status" };
        var excludeFieldsInternalNames = new string[] { "SalesPoint" };


        for (int ii = 0; ii < base.Fields.Count; ii++)
        {
            var currentFiledInternalName = base.Fields[ii].InternalName;

            if (base.IsFieldExcluded(base.Fields[ii]) || 
                                excludeFieldsInternalNames.Contains(currentFiledInternalName))
                continue;


            var fieldIterator = new ListFieldIterator()
            {
                ControlMode = readOnlyFieldsInternalNames.Contains(currentFiledInternalName) ? 
                                SPControlMode.Display : 
                                SPContext.Current.FormContext.FormMode,

                ExcludeFields = string.Join(";#", base.Fields.Cast<SPField>()
                            .Where(ff => ff.InternalName != currentFiledInternalName)
                            .Select(ff => ff.InternalName).ToArray())
            };

            this.Controls.Add(fieldIterator);
        }
    }
}

Листинг 2. Наследник ListFieldIterator который прячет и переводит в ReadOnly заданные поля

Ничего сложного. Здесь для каждого поля, которое нужно отобразить, создается свой ListFieldIterator с нужным ControlMode. В ExcludeFields передается строка содержащая поля которые нужно исключить, т.е. все кроме текущего.

2. Сделать файл MyListForm.aspx и положить его в папку CONTROLTEMPLATES
В MyListForm.aspx скопируйте весь <SharePoint:RenderingTemplate id=«ListForm» runat=«server»>, замените id=«ListForm» на id=«MyListForm”, <SharePoint:ListFieldIterator runat=»server"/> на <My:MyFieldIterator runat=«server»> — Листинг 3.

...
<%@ Register TagPrefix="My" Assembly="$SharePoint.Project.AssemblyFullName$" namespace="My" %>
<SharePoint:RenderingTemplate id="MyListForm" runat="server"><%--<SharePoint:ListFieldIterator runat="server"/>--%>
            <My:MyFieldIterator  runat="server" />
...
</SharePoint:RenderingTemplate>

Листинг 3. Свой шаблон вывода формы списков

Отметим, что MyListForm.aspx обязательно должен лежать в корне CONTROLTEMPLATES, если положить в под-папку не взлетит.

3. Указать для какой формы использовать шаблон MyListForm.
Для этого в ListDefinition укажите Template для нужной формы — Листинг 4.

...
    <Forms>
      <Form Type="DisplayForm" Url="DispForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" />
      <Form Type="EditForm" Url="EditForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" Template="MyListForm" />
      <Form Type="NewForm" Url="NewForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" Template="MyListForm"/>
...

Листинг 4. ListDefinition с указанием шаблонов для вывода форм

Выводы



Использование итераторов по моему мнению, это штука более динамичная и когда делать кастомизацию надо исходить из того чтобы параметры для работы итератора были описаны где нибудь в независимом месте, я всегда использую для этих дел XML и описываю соответствующую схему или генерирую ее динамически. Должен получаться своего рода контроллер. А если нужно что-то единичное сделать, то можно использовать кучу разных простых и быстрых вариантов (SPD, JS.)

Небольшой пример из жизни.

Задача заключалась в том, что есть папка определенного типа контента и все элементы создаваемые внутри папки наследуют некоторые атрибуты и их необходимо скрыть при создании элемента внутри папки, но надо не забывать что элементы из этого типа контента могут создаются и не в папках с наследованием элементов и в этом случае отображать столбцы для заполнения

Мы используем уже существующий пример и добавляем в него - Листинг 5.



private static bool IsParentItem(SPList list, string rootFolderUrl)
        {
            var parentItem = false;
            var check = list.ParentWeb.GetFolder(rootFolderUrl).Exists;
            if (check)
            {
                bool checkItm = list.ParentWeb.GetFolder(rootFolderUrl).Item != null;
                if (checkItm)
                {
                    parentItem = list.ParentWeb.GetFolder(rootFolderUrl).Item.ContentType.Parent.Id == {ContentTypeId};
                }
            }
            return parentItem;
        }

Листинг 5. Проверка родителя

И добавляем дополнительное условие - Листинг 5


 if (base.IsFieldExcluded(base.Fields[ii]) || 
                                (excludeFieldsInternalNames.Contains(currentFiledInternalName)&& isParent))
                continue;

Листинг 5. Добавление в условие из Листнига 2 доп условия

В итоге мы скроем поля которые создались внутри папки и покажем их при создание вне папок.

Для того чтобы не повторяться и не было критики на плагиаты вот источник (Который ссылается тоже на источник).

Комментарии

  1. This operator also lists out its address as Redial Options Office. The registered address is Videoslots Limited The Space, Level 2-3 Alfred Craig Street, Pieta, Malta. We're sorry to hear to} that you've got|that you have} had a foul expertise with withdrawal at our casino, and believe that there was an intentional try to steal cash from you. Your expertise outlined here is actually not the level of customer help we wish to offer, and hope you can to|you probably can} accept our apologizes for any inconveniences triggered. We're very sorry to hear to} you've got had a foul expertise with our games 메리트카지노 these days.

    ОтветитьУдалить

Отправить комментарий

Популярные сообщения из этого блога

Полезности под рукой

Вводное слово