<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-70467739252625072</id><updated>2025-04-09T22:30:01.972+03:00</updated><category term="SharePoint"/><category term="SharePoint2010"/><category term="SharePoint2013"/><category term="JavaScript"/><category term="SharePoint2007"/><category term="XSLT"/><category term="SPList"/><category term="Client Object Model"/><category term="Setup"/><category term="EcmaScript"/><category term="JSGrid"/><category term="Ribbon"/><category term="WIX"/><category term="Workflow"/><category term="блог"/><category term="быстродействие"/><category term="локализация"/><category term="Ajax"/><category term="Microsoft Magic"/><category term="SP.UI.ModalDialog"/><category term="SPField"/><category term="Visual Studio Express"/><category term="кодогенерация"/><category term="CSR"/><category term="HTML5"/><category term="Linq"/><category term="Sandcastle"/><category term="Scrum"/><category term="документация"/><category term="Buzz"/><category term="IoC"/><category term="LUA"/><category term="MAML"/><category term="MEF"/><category term="PropertyGrid"/><category term="Qumo Libro"/><category term="SMS"/><category term="SOLID"/><category term="SSIS"/><category term="flash"/><category term="игры"/><category term="лицензионное ПО"/><title type='text'>Андрей Маркеев: SharePoint блог</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://omlin.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://omlin.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default?start-index=26&amp;max-results=25&amp;redirect=false'/><author><name>Andrei</name><uri>http://www.blogger.com/profile/13548051158654215855</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>113</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-70467739252625072.post-80629022332121654</id><published>2015-10-11T00:37:00.001+03:00</published><updated>2015-10-11T00:43:06.435+03:00</updated><title type='text'>Cisar</title><content type='html'>В этом году я сделал одну большую вещь - Cisar. Это встроенное в браузер (точнее в F12 DevTools) мини-IDE, предназначенное для создания CSR (Client Side Rendering) кастомизаций в SharePoint. Главная фишка Cisar&#39;а в том, что он поддерживает Live Preview, т.е. набираем код и &lt;b&gt;сразу же&lt;/b&gt;, в реальном времени, видим результаты его работы на странице.&lt;br /&gt;
&lt;br /&gt;
Это позволяет работать очень эффективно и создавать решения по кастомизации форм буквально за считанные минуты. Не шучу. Был даже реальный случай: коллега на работе оценил некоторую задачу по кастомизации форм в час работы, там надо было заменить текстовое поле dropdown&#39;ом, причем он (коллега) с CSR &lt;b&gt;очень хорошо&lt;/b&gt; дружит. Я с ним поспорил на пиво, что смогу сделать за 3 минуты с помощью Cisar. Проиграл: сделал за 5 :)&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhoK5pI10o9ZWyJGSB1tiKOTjU9Spjov8Jp0UlhG8f0-g8DpOVxzQk2MD9F2_Jq2rCgnT8F1o8GO01trKBVpz79nL0QXqP9Wf12WDDydsoN8m3i8q2ATZUzTmgdsLeJlfqwS_5mGjUnH3k/s1600/cisar.gif&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhoK5pI10o9ZWyJGSB1tiKOTjU9Spjov8Jp0UlhG8f0-g8DpOVxzQk2MD9F2_Jq2rCgnT8F1o8GO01trKBVpz79nL0QXqP9Wf12WDDydsoN8m3i8q2ATZUzTmgdsLeJlfqwS_5mGjUnH3k/s1600/cisar.gif&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div&gt;
Поддерживается CSR для:&lt;/div&gt;
&lt;div&gt;
&lt;ol&gt;
&lt;li&gt;Форм списков&lt;/li&gt;
&lt;li&gt;Представлений списков&lt;/li&gt;
&lt;li&gt;Представлений списков в режиме Quick Edit&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
НЕ поддерживается на данном этапе CSR для результатов поиска, и вообще Display Templates как класс. Надеюсь это добавить в будущем, но это технически нетривиально.&lt;/div&gt;
&lt;/div&gt;
&lt;br /&gt;
До последнего времени Cisar плохо работал с не-root сайт-коллекциями, но у меня наконец-то дошли руки это поправить и теперь проблем быть не должно. Но версия все еще Beta, так что огромная просьба, всем кто будет использовать, пишите багрепорты!! Сюда в комментарии, или на GitHub, куда-нибудь в общем... :)&lt;br /&gt;
&lt;br /&gt;
Cisar полностью бесплатен, open source, лицензия &quot;Public Domain&quot; (это означает, делайте вообще все что угодно с ним, никаких ограничений).&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
С технической точки зрения Cisar - это расширение для Chrome, написанное кстати на TypeScript. Для подсветки синтаксиса используется редактор codemirror. Для отображения списка файлов используется KnockoutJs. Для Live Preview используются результаты нескольких недель копания в кишках CSR, если вы думаете что это просто eval, можете посмотреть код :)&lt;br /&gt;
&lt;br /&gt;
Исходники доступны&amp;nbsp;&lt;a href=&quot;https://github.com/andrei-markeev/cisar&quot;&gt;на GitHub&lt;/a&gt;.&lt;br /&gt;
Само расширение можно скачать &lt;a href=&quot;https://chrome.google.com/webstore/detail/cisar/nifbdojdggkboiifaklkamfpjcmgafpo&quot;&gt;из Chrome Web Store&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Также, если кто-то вдруг пропустил мои статьи по CSR, с множеством примеров кастомизаций (большинство из которых были созданы с помощью Cisar), ссылки ниже (статьи на английском):&lt;br /&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.codeproject.com/Articles/620110/SharePoint-Client-Side-Rendering-List-Views&quot;&gt;SharePoint Client Side Rendering: List Views&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.codeproject.com/Articles/610259/SharePoint-Client-Side-Rendering-List-Forms&quot;&gt;SharePoint Client Side Rendering: List Forms&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.codeproject.com/Articles/888923/SharePoint-Client-Side-Rendering-List-Forms-p&quot;&gt;SharePoint Client Side Rendering: List Forms&amp;nbsp;+ KnockoutJs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
P.S. На самом деле так привык к Cisar, и так удобно, что теперь уже даже пытаюсь его использовать для любого клиентского кода. И как я раньше писал JSOM-код без intellisense!? :)&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://omlin.blogspot.com/feeds/80629022332121654/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://omlin.blogspot.com/2015/10/cisar.html#comment-form' title='Комментарии: 19'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/80629022332121654'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/80629022332121654'/><link rel='alternate' type='text/html' href='http://omlin.blogspot.com/2015/10/cisar.html' title='Cisar'/><author><name>Andrei</name><uri>http://www.blogger.com/profile/13548051158654215855</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhoK5pI10o9ZWyJGSB1tiKOTjU9Spjov8Jp0UlhG8f0-g8DpOVxzQk2MD9F2_Jq2rCgnT8F1o8GO01trKBVpz79nL0QXqP9Wf12WDDydsoN8m3i8q2ATZUzTmgdsLeJlfqwS_5mGjUnH3k/s72-c/cisar.gif" height="72" width="72"/><thr:total>19</thr:total></entry><entry><id>tag:blogger.com,1999:blog-70467739252625072.post-4825815876435991702</id><published>2015-10-09T01:53:00.001+03:00</published><updated>2015-10-09T01:58:00.386+03:00</updated><title type='text'>Про собеседования</title><content type='html'>Прочитал статью &lt;a href=&quot;http://steve-yegge.blogspot.fi/2008/03/get-that-job-at-google.html&quot;&gt;Get that job at Google&lt;/a&gt;, и очень сильно разочаровался! Ситуация подтвердилась и другими источниками: оказывается, в больших компаниях типа Google и Facebook собеседования далеко не такие качественные, как можно было бы подумать :(&lt;br&gt;
&lt;br&gt;
В частности, я был крайне удивлен что проведение технических собеседований доверяется обычным программистам без серьезной подготовки их для этой работы. И они приносят собственновыдуманные вопросы, скорее всего не прорецензированные более опытными коллегами... В итоге имеем что имеем: например, требуют писать код на доске (whiteboard), задают алгоритмические задачки олимпиадного типа и прочую чушь, с которой обычный программист никогда не имеет дела в реальной жизни (в том числе они сами). В итоге собеседование превращается в экзамен и приводит к огромному числу неправильных оценок кандидатов, причем ребята из Google утверждают, что это исключительно &amp;quot;false negative&amp;quot;, тогда как я почти уверен, что &amp;quot;false positive&amp;quot; там тоже немало.&lt;br&gt;
&lt;div&gt;
&lt;ol&gt;
&lt;/ol&gt;
&lt;/div&gt;
Я давно интересуюсь собеседованиями, и есть кое-какой опыт в этой области, причем побывал на обеих &amp;quot;сторонах баррикад&amp;quot;: составлял вопросы и проводил собеседования когда работал в Softline; ну и конечно приличное количество раз ходил собеседовался в разные компании - в Костроме, Москве, Питере и Хельсинки, включая например Microsoft (кстати, за последние 5 лет не услышал ни одного отказа: 100% собеседований были успешными и заканчивались предложением работы).&lt;br&gt;
&lt;br&gt;
Итак, ниже мои мысли по тому что нужно проверять на собеседованиях и как, и что не нужно, и почему.&lt;br&gt;
&lt;a href=&quot;http://omlin.blogspot.com/2015/10/blog-post.html#more&quot;&gt;Читать дальше »&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://omlin.blogspot.com/feeds/4825815876435991702/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://omlin.blogspot.com/2015/10/blog-post.html#comment-form' title='Комментарии: 12'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/4825815876435991702'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/4825815876435991702'/><link rel='alternate' type='text/html' href='http://omlin.blogspot.com/2015/10/blog-post.html' title='Про собеседования'/><author><name>Andrei</name><uri>http://www.blogger.com/profile/13548051158654215855</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-70467739252625072.post-1846102738156493845</id><published>2014-10-22T10:15:00.000+04:00</published><updated>2015-01-21T00:31:49.899+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript"/><category scheme="http://www.blogger.com/atom/ns#" term="JSGrid"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint2013"/><title type='text'>Своё контекстное меню в JsGrid</title><content type='html'>&lt;br&gt;
Часто возникающая задача – это прикрутить к ячейкам JsGrid контекстное меню с некоторыми дополнительными функциями. Мой любимый пример – это контекстный фильтр, когда кликаешь по ячейке правой мышой, и жмешь фильтровать по значению ячейки. Очень удобно.&lt;br&gt;
&lt;br&gt;
В прошлом посте я объяснял, как устроена система событий JsGrid, и оказывается, как раз с помощью события SP.JsGrid.EventType.OnRightClick - можно решить задачу с контекстным меню. Помимо события, впрочем, надо еще уметь само контекстное меню создавать. И оказывается, JsGrid имеет API и для этого тоже!&lt;br&gt;
&lt;br&gt;
&lt;h4&gt;
&lt;/h4&gt;&lt;a href=&quot;http://omlin.blogspot.com/2014/10/jsgrid-contextMenu.html#more&quot;&gt;Читать дальше »&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://omlin.blogspot.com/feeds/1846102738156493845/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://omlin.blogspot.com/2014/10/jsgrid-contextMenu.html#comment-form' title='Комментарии: 6'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/1846102738156493845'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/1846102738156493845'/><link rel='alternate' type='text/html' href='http://omlin.blogspot.com/2014/10/jsgrid-contextMenu.html' title='Своё контекстное меню в JsGrid'/><author><name>Andrei</name><uri>http://www.blogger.com/profile/13548051158654215855</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKjm6-gBnKDknSZM8I6KhgBh9P1jrPVqMRBGgbMVSASFCY1f8U0xKqRXhiLfdkhDL37EgI2o2WeFVJjX7TNprb_6Nc-wF80EguHyKoR9z1auZA43Y6nPXSe2V8rZGGYh8GvHhyphenhyphennm3SXpI/s72-c?imgmax=800" height="72" width="72"/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-70467739252625072.post-8334384949034925931</id><published>2014-10-21T09:30:00.000+04:00</published><updated>2014-10-21T09:30:01.157+04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript"/><category scheme="http://www.blogger.com/atom/ns#" term="JSGrid"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint2013"/><title type='text'>Система событий JSGrid</title><content type='html'>В &lt;a href=&quot;http://omlin.blogspot.com/2014/10/jsgrid-highlight.html&quot;&gt;предыдущей статье&lt;/a&gt; я описывал, как осуществляется подсветка строк и отдельных ячеек в JsGrid. Но если вы попробовали использовать это решение, вы наверняка заметили одну недоделку: подсветка не обновляется при редактировании соответствующего значения.&lt;br&gt;
Да, к сожалению, JsGrid это вам не KnockoutJs, так что обновлять придется самостоятельно. Впрочем, делается это очень легко.&lt;br&gt;
В этом посте я расскажу про систему событий в JsGrid: как подписываться на события, какие интересные события JsGrid предоставляет, и приведу пример про обновление подсветки строки после редактирования ячеек этой строки.&lt;br&gt;
&lt;a href=&quot;http://omlin.blogspot.com/2014/10/jsgrid-events.html#more&quot;&gt;Читать дальше »&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://omlin.blogspot.com/feeds/8334384949034925931/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://omlin.blogspot.com/2014/10/jsgrid-events.html#comment-form' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/8334384949034925931'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/8334384949034925931'/><link rel='alternate' type='text/html' href='http://omlin.blogspot.com/2014/10/jsgrid-events.html' title='Система событий JSGrid'/><author><name>Andrei</name><uri>http://www.blogger.com/profile/13548051158654215855</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-70467739252625072.post-180056759851264507</id><published>2014-10-20T09:00:00.000+04:00</published><updated>2014-10-20T09:00:04.764+04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript"/><category scheme="http://www.blogger.com/atom/ns#" term="JSGrid"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint2013"/><title type='text'>Выделение цветом важных данных… в JSGrid!</title><content type='html'>Пока &lt;a href=&quot;http://omlin.blogspot.fi/2014/10/sharepoint-jsgrid.html&quot;&gt;дефинишены пишутся&lt;/a&gt;, решил написать про некоторые простые методы работы с JSGrid, на примере подсветки данных в гриде. &lt;br&gt;
&lt;br&gt;
Также в статье приводится довольно много сведений общего плана про JsGrid, которые очень важны для понимания, как это все работает.&lt;br&gt;
&lt;br&gt;
&lt;a href=&quot;http://omlin.blogspot.com/2014/10/jsgrid-highlight.html#more&quot;&gt;Читать дальше »&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://omlin.blogspot.com/feeds/180056759851264507/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://omlin.blogspot.com/2014/10/jsgrid-highlight.html#comment-form' title='Комментарии: 7'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/180056759851264507'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/180056759851264507'/><link rel='alternate' type='text/html' href='http://omlin.blogspot.com/2014/10/jsgrid-highlight.html' title='Выделение цветом важных данных… в JSGrid!'/><author><name>Andrei</name><uri>http://www.blogger.com/profile/13548051158654215855</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhOsTvyuHGJiVWVI6G79f-RzcgvFcIzUnnrHQ1MBWsMyix5aQj6azT3vEtWirPptQG2SwPirPh6Z6DF7KMN9I6J5UyyVu_hrMnPU6uxg3QBLIsIjMpLLyOgb5s2vRFK7JnV8uLG9wYRsRw/s72-c?imgmax=800" height="72" width="72"/><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-70467739252625072.post-3480203001625744423</id><published>2014-10-14T09:00:00.000+04:00</published><updated>2014-10-20T04:10:09.107+04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript"/><category scheme="http://www.blogger.com/atom/ns#" term="JSGrid"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint2010"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint2013"/><title type='text'>Документирую SharePoint JSGrid</title><content type='html'>Тружусь сейчас над TypeScript-дефинишенами для JsGrid. Работа долгая и тяжкая: для каждой-каждой функции в JS файле из 24.5k строк нужно определить типы параметров и возвращаемого значения, понять что эта функция делает, и все это описать. Потратил уже несколько дней, по 5+ часов, и пока еще только в начале пути... Между прочим, даже главный шарепойнтовский файл, SP.debug.js, имеет меньший размер - ~21k строк...&lt;br&gt;
&lt;br&gt;
Скриншот процесса:&lt;br&gt;
&lt;br&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0UeCqRvcEU9sF0aJE5FG477EfR7kPoFff_wIDDbo5IOHWEx1uZ0mutrvNBO5427vRyAuqpiIR4hZ7Kqi3fySo7rJ__k52pk5rfYsTP0e9f0X0owsOb9ibj81QYO_E66ejHk2R5SUTl-g/s1600/jsgrid_dev.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0UeCqRvcEU9sF0aJE5FG477EfR7kPoFff_wIDDbo5IOHWEx1uZ0mutrvNBO5427vRyAuqpiIR4hZ7Kqi3fySo7rJ__k52pk5rfYsTP0e9f0X0owsOb9ibj81QYO_E66ejHk2R5SUTl-g/s1600/jsgrid_dev.png&quot; style=&quot;height: auto; width: 800px;&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;a href=&quot;http://omlin.blogspot.com/2014/10/sharepoint-jsgrid.html#more&quot;&gt;Читать дальше »&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://omlin.blogspot.com/feeds/3480203001625744423/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://omlin.blogspot.com/2014/10/sharepoint-jsgrid.html#comment-form' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/3480203001625744423'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/3480203001625744423'/><link rel='alternate' type='text/html' href='http://omlin.blogspot.com/2014/10/sharepoint-jsgrid.html' title='Документирую SharePoint JSGrid'/><author><name>Andrei</name><uri>http://www.blogger.com/profile/13548051158654215855</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0UeCqRvcEU9sF0aJE5FG477EfR7kPoFff_wIDDbo5IOHWEx1uZ0mutrvNBO5427vRyAuqpiIR4hZ7Kqi3fySo7rJ__k52pk5rfYsTP0e9f0X0owsOb9ibj81QYO_E66ejHk2R5SUTl-g/s72-c/jsgrid_dev.png" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-70467739252625072.post-296370255216827490</id><published>2014-10-11T16:30:00.000+04:00</published><updated>2014-10-11T16:51:12.870+04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint2007"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint2010"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint2013"/><title type='text'>Ускоряем SharePoint-разработку</title><content type='html'>&lt;div&gt;
SharePoint особенно знаменит затыками &quot;на последнем километре&quot; и багами в совершенно неожиданных местах. Поэтому чем больше решение тестируется, и чем раньше начинаешь тестировать - тем лучше.&lt;/div&gt;
&lt;br /&gt;
Однако, тестировать SharePoint-решения не так-то просто. Их ведь надо еще задеплоить. А пока деплоишь, заснуть можно!... И потом сиди вспоминай, что вообще протестировать-то хотел...&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;br /&gt;
И ведь все знают, что нередко бывает так: правишь пару символов - это занимает буквально секунды, и потом деплоишь пять минут, чтобы посмотреть результат. Потом видишь что не помогло - и по новой, еще пять минут деплоя... И не думайте, что концентрация от этого не теряется. Еще как.&lt;br /&gt;
&lt;br /&gt;
Смешно сказать, но я до сих пор вспоминаю &lt;a href=&quot;https://spvisualdev.codeplex.com/&quot;&gt;SPVisualDev&lt;/a&gt;, расширение для Visual Studio для работы с SharePoint 2007. Мгновенное развертывание в 12 hive, отличная поддержка удаленной разработки и отладки, всё удобно, быстро и просто. Этого в SharePoint Developer Tools нет и в помине даже сейчас, в 2014!...&lt;br /&gt;
&lt;br /&gt;
Да, к сожалению, SharePoint с точки зрения скорости разработки сильно далеко от того, что сейчас происходит во &quot;внешнем мире&quot;. А происходит, к слову, там, вот что:&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;
Тем временем во &quot;внешнем мире&quot;...&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Проект IDE &lt;a href=&quot;http://lighttable.com/&quot;&gt;Light Table&lt;/a&gt; набрал $300k на Kickstarter. Основная идея проекта - в &quot;живой разработке&quot;, когда IDE &lt;u&gt;всегда&lt;/u&gt;&amp;nbsp;находится в режиме отладки (!). Т.е. обычного режима &lt;i&gt;не-отладки&lt;/i&gt; просто не бывает. Только начали писать код - тут же можно смотреть состояние переменных, и т.д.&lt;/li&gt;
&lt;li&gt;Многие современные IDE поддерживают режим &quot;live development&quot;. Пример - опенсурсная IDE Brackets. Вот одноминутная демка:
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;iframe allowfullscreen=&#39;allowfullscreen&#39; webkitallowfullscreen=&#39;webkitallowfullscreen&#39; mozallowfullscreen=&#39;mozallowfullscreen&#39; width=&#39;520&#39; height=&#39;366&#39; src=&#39;https://www.youtube.com/embed/Nhvj1NYC3Uc?feature=player_embedded&#39; frameborder=&#39;0&#39;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;Visual Studio и ASP.Net развивают проект &quot;Browser Link&quot;. Идея состоит в том, чтобы инжектить Signal-R скрипт на страницу, что позволяет в дальнейшем этой страницей управлять: релоадить целиком или частями, изменять, и т.д. &quot;Browser Link&quot; можно расширять с помощью Visual Studio extensions. В составе Web Essentials есть несколько крайне интересных расширений такого плана. Скотт Хансельман в этом 4х-минутном видео подробно все это демонстрирует:
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;iframe allowfullscreen=&#39;allowfullscreen&#39; webkitallowfullscreen=&#39;webkitallowfullscreen&#39; mozallowfullscreen=&#39;mozallowfullscreen&#39; width=&#39;520&#39; height=&#39;366&#39; src=&#39;https://www.youtube.com/embed/q1J6kLeoY2E?feature=player_embedded&#39; frameborder=&#39;0&#39;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;Visual Studio &quot;14&quot; CTP 4 по умолчанию использует open source компилятор &lt;a href=&quot;http://msdn.microsoft.com/en-us/vstudio/roslyn.aspx&quot;&gt;Roslyn&lt;/a&gt;, который имеет расширенные средства для работы с неполными синтаксическими деревьями, благодаря чему им удалось сделать on-fly incremental compilation. Идея в том, чтобы пропустить шаг Build. Т.е. меняем код, сохраняем, переходим в браузер, F5 - и смотрим изменения.&lt;/li&gt;
&lt;li&gt;Помимо общеизвестного jsFiddle, появляется все больше и больше других Fiddle&#39;ов, крайне интересных! Например, проект &lt;a href=&quot;https://dotnetfiddle.net/&quot;&gt;dotNetFiddle&lt;/a&gt; не только позволяет писать C# код онлайн, но также предоставляет режим, в котором можно тестировать полномасштабное ASP.Net MVC приложение (выберите Project Type: MVC)!&lt;/li&gt;
&lt;/ol&gt;
&lt;br /&gt;
&lt;br /&gt;
И т.д., список можно продолжать. Но я думаю вы поняли идею: все осознают, что чем меньше задержка между написанным кодом и увиденным результатом, тем лучше. И к этому идут. Но что можем сделать мы, SharePoint-разработчики?&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;
Оказывается, и в SharePoint тоже можно сделать немало!&lt;/h4&gt;
&lt;br /&gt;
Для начала, продолжая мысль из поста &lt;a href=&quot;http://omlin.blogspot.fi/2014/08/apps.html&quot;&gt;про скрытую прелесть provider-hosted Apps&lt;/a&gt;, ну как бы все современные вещи можно там использовать без ограничений :) Так что всё что выше описано, нам по большому счету тоже доступно. Надо просто не забыть воспользоваться.&lt;br /&gt;
&lt;br /&gt;
Во-вторых, кратко вернусь к SPVisualDev. Это open source расширение было написано ОДНИМ человеком в 2008 году. Получается, не настолько уж это и сложно?... ;)&lt;br /&gt;
&lt;br /&gt;
Дальше. Давайте подумаем про BrowserLink. Можно ли что-то похожее использовать в SharePoint? Я думаю - да. Ведь BrowserLink это ни что иное, как банальный SignalR. Если заинжектить аналогичный SignalR скрипт в masterpage SharePoint-сайта, то мы получим точно такое же &quot;живое&quot; соединение Visual Studio и SharePoint. Я думаю можно просто выдрать из страницы то, что Visual Studio инжектит, и запихнуть в SharePoint, и оно будет работать. Не успел проверить пока.&lt;br /&gt;
&lt;br /&gt;
Дальше. А что насчет jsFiddle и ASP.Net MVC fiddle? Можно ли сделать собственный SharePoint fiddle? ДА БЕЗ ПРОБЛЕМ! Вот например оцените, проект JSON fiddle:&lt;br /&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;Блог пост: &lt;a href=&quot;http://blog.thekid.me.uk/post/Introducing-the-JSOM-Fiddle-SharePoint-App&quot;&gt;Introducing JSOM fiddle SharePoint app&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;В Office Store: &lt;a href=&quot;https://store.office.com/jsom-fiddle-WA104320165.aspx?lc=en-gb&amp;amp;assetid=WA104320165&amp;amp;ui=en-US&amp;amp;rs=en-GB&amp;amp;ad=GB&quot;&gt;JSOM fiddle app&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/TheKidVince/JSOM-Fiddle&quot;&gt;Исходный код на Github&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
Опять же. Сделано буквально на коленке, какой-то мужик посидел пару вечеров и написал. Вы, дорогой читатель, тоже могли бы такое написать, даже в одиночку. И вас, дорогие читатели, смею заметить, дофига.&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;
Моя попытка: CamlJs-Console&lt;/h4&gt;
&lt;br /&gt;
Вообще, на удивление, многие вещи не настолько сложные, как кажутся. Примерно в середине сентября я начал работать над крайне интересным проектом под названием &lt;a href=&quot;https://github.com/andrei-markeev/camljs-console&quot;&gt;CamlJs-Console&lt;/a&gt;. Это расширение для хрома, позволяющее создавать CamlJs-запросы в режиме live development, очень похожем на пример выше про Brackets. Пишешь - и сразу же видишь результат.&lt;br /&gt;
&lt;br /&gt;
Оказалось, что Chrome Extensions пишутся на HTML+CSS+JavaScript. Очень просто. При желании можно даже создавать Chrome Extension&amp;nbsp;+ Web App (или даже SharePoint App) из одного исходного кода...&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
БЛИН! Я когда только-только сделал самую первую версию у себя на локальной машине в 3 часа ночи :), я сидел тестировал и не мог остановиться. Это настолько отличалось от вот этого &quot;поправил-5 минут деплой&quot;, что чувствовалось как магия какая-то. Серьезно :)&lt;br /&gt;
&lt;br /&gt;
Общий вид:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6Az34OYzv5swfle2K08saleYuYg4LL-uz0uMzcCrHgloNmDYuE-uj4sMqUWK_8RL9SdKU8DPbfVj_EDTZRuMah2-7uNrSVESKksR_aw6vfgmOtht7gizxdqTf-umaetCku5h6WFCmk6k/s1600/full-view.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6Az34OYzv5swfle2K08saleYuYg4LL-uz0uMzcCrHgloNmDYuE-uj4sMqUWK_8RL9SdKU8DPbfVj_EDTZRuMah2-7uNrSVESKksR_aw6vfgmOtht7gizxdqTf-umaetCku5h6WFCmk6k/s1600/full-view.png&quot; height=&quot;328&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
А вот live preview данных из списка:&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcnjIgqIb7dNKwCH2z7M4whiXJMf9xCjSIDaVzXvEygNaJ9glurHVY0Ynak9xh9aAB86pbX7hA-W0PAHICgbv74J1qszEo3QMfH6nnObPWdR1ayQs8ek4zZMJvyQbYQ3wmb-sonhaURJ4/s1600/live-data-preview.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcnjIgqIb7dNKwCH2z7M4whiXJMf9xCjSIDaVzXvEygNaJ9glurHVY0Ynak9xh9aAB86pbX7hA-W0PAHICgbv74J1qszEo3QMfH6nnObPWdR1ayQs8ek4zZMJvyQbYQ3wmb-sonhaURJ4/s1600/live-data-preview.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Мне даже удалось подцепить туда интеллисенс (на основе TypeScript Language Service - ведь как известно, TS является расширением над JS, т.е. любой валидный JS-код является также и валидным TS-кодом):&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRKGkujlKSz6CKM9m3dMlwny400VMm8jhQ8K3RmHzw1lSHjWVj1_VeV6IhtzH0c1QJehfQC0YxwuF8xixDVFX6AzNhz-B7HFG3t4RcQkokgagL4Sg-GlJ0YUlUNm8pMPHUPK75J4kPey0/s1600/intellisense.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRKGkujlKSz6CKM9m3dMlwny400VMm8jhQ8K3RmHzw1lSHjWVj1_VeV6IhtzH0c1QJehfQC0YxwuF8xixDVFX6AzNhz-B7HFG3t4RcQkokgagL4Sg-GlJ0YUlUNm8pMPHUPK75J4kPey0/s1600/intellisense.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
И более того, мне даже удалось сделать интеллисенс лучше, чем TS-интеллисенс в Visual Studio! Потому что ведь у меня были живые списки. И их поля... :)&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEguRv9E87UNDf6MvgxIfh7ITS49iyG4g7C2kWSS8YjCMqIpHrWxbHA3y41fSwCuGrpBuALL7vJgUjhpL3XceAJ9iNy-lgYbUbKa7lydhzdbNt7INcTMqVm_3x-Lpt-F1cNq50jR7iJ_ucQ/s1600/intellisense-fields.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEguRv9E87UNDf6MvgxIfh7ITS49iyG4g7C2kWSS8YjCMqIpHrWxbHA3y41fSwCuGrpBuALL7vJgUjhpL3XceAJ9iNy-lgYbUbKa7lydhzdbNt7INcTMqVm_3x-Lpt-F1cNq50jR7iJ_ucQ/s1600/intellisense-fields.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Мне кажется, получилось здорово! И заняло каких-то пару недель, причем большую часть времени возился с интеллисенсом.&lt;br /&gt;
&lt;br /&gt;
Преимуществ у Chrome Extension немало: не надо аутентифицироваться, не надо ничего ставить на сайт (в отличие от того же SharePoint App). Можно тестировать и онлайн сайты, и на dev виртуалке, и что особенно ценно - зайти на production и там проверить запрос, на реальных данных (!). Интеграция работает через JSOM, но можно реализовать вариант на веб-сервисах (через SPServices например), и тогда будет работать даже с SharePoint 2007 (сейчас только SP2010 и SP2013).&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;
Что дальше?&lt;/h4&gt;
&lt;br /&gt;
Ооооо... у меня полно идей, просто миллион! Можно делать extension&#39;ы наподобие CamlJs - для работы с конкретным API, решения конкретных проблем. Можно делать более широкопрофильные, наподобие JSOM fiddle, но именно в виде Chrome extension. Можно копать в сторону интеграции Visual Studio и SharePoint, создания чего-то похожего на BrowserLink. Можно подумать о гибридных решениях, Visual Studio -&amp;gt; Chrome Extension -&amp;gt; SharePoint.&lt;br /&gt;
&lt;br /&gt;
И это все может значительно улучшить наш процесс работы с SharePoint. Значительно!&lt;br /&gt;
&lt;br /&gt;
Коллега с работы делает сейчас потрясающую штуку, как раз под впечатлением от CamlJs-Console. Крайне легко делается, но возможности открываются потрясающие. Смысл в том, что в Chrome через F12 можно редактировать файлы, подгруженные на страницу. Но конечно эти изменения никуда не сохраняются. Ну а вот он сделал так, что сохраняются, обратно в SharePoint :) И кода там - &lt;b&gt;50 строк&lt;/b&gt; :))). Проект пока на супер-начальной стадии, поэтому если захочется потестировать, тестируйте аккуратно и только на dev-окружении please :)&amp;nbsp;&lt;a href=&quot;https://github.com/tavikukko/Chrome-SP-Editor&quot;&gt;Ссылка вот&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;
Заключение&lt;/h4&gt;
&lt;br /&gt;
Я из всей этой истории главное вот что понял: все в наших руках. Не надо ждать MS или еще кого. Мы сами можем.&lt;br /&gt;
&lt;br /&gt;
P.S. Если у кого есть идеи/мысли на этот счет, с удовольствием поучаствую в обсуждении - кидайте комментарии! :)</content><link rel='replies' type='application/atom+xml' href='http://omlin.blogspot.com/feeds/296370255216827490/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://omlin.blogspot.com/2014/10/instant-development.html#comment-form' title='Комментарии: 6'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/296370255216827490'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/296370255216827490'/><link rel='alternate' type='text/html' href='http://omlin.blogspot.com/2014/10/instant-development.html' title='Ускоряем SharePoint-разработку'/><author><name>Andrei</name><uri>http://www.blogger.com/profile/13548051158654215855</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6Az34OYzv5swfle2K08saleYuYg4LL-uz0uMzcCrHgloNmDYuE-uj4sMqUWK_8RL9SdKU8DPbfVj_EDTZRuMah2-7uNrSVESKksR_aw6vfgmOtht7gizxdqTf-umaetCku5h6WFCmk6k/s72-c/full-view.png" height="72" width="72"/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-70467739252625072.post-7951510853536721147</id><published>2014-09-22T09:20:00.000+04:00</published><updated>2014-09-22T09:20:00.350+04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint2013"/><category scheme="http://www.blogger.com/atom/ns#" term="SPList"/><category scheme="http://www.blogger.com/atom/ns#" term="быстродействие"/><title type='text'>Загадочно бесполезный SPList.GetDataTable</title><content type='html'>Копал SPQuery в dotPeek, и наткнулся на интересный кусок кода:&lt;br&gt;
&lt;br&gt;
&lt;pre&gt;&lt;span style=&quot;color: #7f0055; font-weight: bold;&quot;&gt;if&lt;/span&gt; (&lt;span style=&quot;color: #7f0055; font-weight: bold;&quot;&gt;this&lt;/span&gt;.m_Query.ConsiderManagedPipe
    &amp;amp;&amp;amp; &lt;span style=&quot;color: #7f0055; font-weight: bold;&quot;&gt;this&lt;/span&gt;.m_Query.SafeArrayFlags == &lt;span style=&quot;color: #7f0055; font-weight: bold;&quot;&gt;null&lt;/span&gt; 
    &amp;amp;&amp;amp; (&lt;span style=&quot;color: #7f0055; font-weight: bold;&quot;&gt;this&lt;/span&gt;.m_Query.CalendarDate == DateTime.MinValue &amp;amp;&amp;amp; !&lt;span style=&quot;color: #7f0055; font-weight: bold;&quot;&gt;this&lt;/span&gt;.m_Query.IncludeMandatoryColumns) 
    &amp;amp;&amp;amp; (&lt;span style=&quot;color: #7f0055; font-weight: bold;&quot;&gt;this&lt;/span&gt;.m_Query.ViewFieldsOnly 
        &amp;amp;&amp;amp; (&lt;span style=&quot;color: #7f0055; font-weight: bold;&quot;&gt;this&lt;/span&gt;.m_Query.DataTableOptions &amp;amp; SPListGetDataTableOptions.RetrieveLookupIdsOnly) != SPListGetDataTableOptions.None 
        &amp;amp;&amp;amp; ((&lt;span style=&quot;color: #7f0055; font-weight: bold;&quot;&gt;this&lt;/span&gt;.m_Query.DataTableOptions &amp;amp; SPListGetDataTableOptions.UseBooleanDataType) != SPListGetDataTableOptions.None 
        &amp;amp;&amp;amp; (&lt;span style=&quot;color: #7f0055; font-weight: bold;&quot;&gt;this&lt;/span&gt;.m_Query.DataTableOptions &amp;amp; SPListGetDataTableOptions.UseCalculatedDataType) != SPListGetDataTableOptions.None)) 
    &amp;amp;&amp;amp; (!&lt;span style=&quot;color: #7f0055; font-weight: bold;&quot;&gt;string&lt;/span&gt;.IsNullOrEmpty(&lt;span style=&quot;color: #7f0055; font-weight: bold;&quot;&gt;this&lt;/span&gt;.m_Query.ViewFields) 
    &amp;amp;&amp;amp; &lt;span style=&quot;color: #7f0055; font-weight: bold;&quot;&gt;string&lt;/span&gt;.IsNullOrEmpty(&lt;span style=&quot;color: #7f0055; font-weight: bold;&quot;&gt;this&lt;/span&gt;.m_Query.ViewAttributes) 
    &amp;amp;&amp;amp; (&lt;span style=&quot;color: #7f0055; font-weight: bold;&quot;&gt;this&lt;/span&gt;.m_List.BaseType != SPBaseType.DiscussionBoard &amp;amp;&amp;amp; !&lt;span style=&quot;color: #7f0055; font-weight: bold;&quot;&gt;this&lt;/span&gt;.QueryIncludesMultiValueLookup(&lt;span style=&quot;color: #7f0055; font-weight: bold;&quot;&gt;this&lt;/span&gt;.m_Query.ViewFields)) 
    &amp;amp;&amp;amp; !&lt;span style=&quot;color: #7f0055; font-weight: bold;&quot;&gt;this&lt;/span&gt;.m_List.HasUniqueScopes))
{
      ULS.SendTraceTag(963012918U, (ULSCatBase) ULSCat.msoulscat_WSS_Database, ULSTraceLevel.Verbose, &lt;span style=&quot;color: #2a00ff;&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #2a00ff;&quot;&gt;SPListItemCollection.EnsureListItemData: Retrieving data through the managed pipe.&lt;/span&gt;&lt;span style=&quot;color: #2a00ff;&quot;&gt;&amp;quot;&lt;/span&gt;);
      &lt;span style=&quot;color: #7f0055; font-weight: bold;&quot;&gt;this&lt;/span&gt;.m_bUseManagedPipe = &lt;span style=&quot;color: #7f0055; font-weight: bold;&quot;&gt;true&lt;/span&gt;;
}
&lt;/pre&gt;
&lt;br&gt;
Интересно, думаю. Неспроста! Сами посмотрите: условия все такие, логически связанные с performance.
Может это какой-нибудь хитрый performance-boost такой?&lt;br&gt;
&lt;br&gt;
Ну, начал разбираться...
&lt;br&gt;
&lt;br&gt;
&lt;a href=&quot;http://omlin.blogspot.com/2014/09/splistgetdatatable.html#more&quot;&gt;Читать дальше »&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://omlin.blogspot.com/feeds/7951510853536721147/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://omlin.blogspot.com/2014/09/splistgetdatatable.html#comment-form' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/7951510853536721147'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/7951510853536721147'/><link rel='alternate' type='text/html' href='http://omlin.blogspot.com/2014/09/splistgetdatatable.html' title='Загадочно бесполезный SPList.GetDataTable'/><author><name>Andrei</name><uri>http://www.blogger.com/profile/13548051158654215855</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwAWCfNQx3B4vQKqvy_-9P8PRZWtnQLxLz8yFbMST98h5owtKJjsM3SzNHabQOtieb9dyjZ8eoCGip0g34Y9v-GhHz9lyX5Hn5XMxuhPl39nPaPb3pPF1kJ-tx0y1xxQfH4zp-fWLQgsA/s72-c/list_thresold.png" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-70467739252625072.post-703271534158092638</id><published>2014-09-20T21:26:00.000+04:00</published><updated>2014-09-20T23:01:28.690+04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Client Object Model"/><category scheme="http://www.blogger.com/atom/ns#" term="CSR"/><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint2007"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint2010"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint2013"/><category scheme="http://www.blogger.com/atom/ns#" term="XSLT"/><title type='text'>3 простых способа подружить KnockoutJs и SharePoint</title><content type='html'>Попал на старый проект, SharePoint 2010. Бывает, что тут сделаешь! Спасаюсь от скуки только благодаря &lt;a href=&quot;http://knockoutjs.com/index.html&quot;&gt;KnockoutJs&lt;/a&gt; :) Всвязи с чем - этот пост.&lt;br&gt;
&lt;br&gt;
KnockoutJs как MVVM фреймворк на самом деле ничем не уступает тому же Angular&amp;#39;у. Единственная вещь, которую нужно очень хорошо изучить и вызубрить в Knockout - это когда скобки &lt;b style=&quot;background-color: yellow;&quot;&gt;()&lt;/b&gt; нужны, а когда нет, и как этот &lt;a href=&quot;http://knockoutjs.com/documentation/observables.html&quot;&gt;ko observable wrapping&lt;/a&gt; вообще работает. Преодолев этот порог, больше с Knockout проблем не возникает. Angular конечно помощнее, более фундаментальный, но и всякой магии в нем намного больше, траблшутить крайне сложно, и модель освоения Angular действительно вот такая (проверено на собственном опыте):&lt;br&gt;
&lt;br&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://www.bennadel.com/resources/uploads/2013/feelings_about_angularjs_over_time.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://www.bennadel.com/resources/uploads/2013/feelings_about_angularjs_over_time.png&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;
Так что, в своих SharePoint-проектах я преимущественно использую именно Knockout. И в этом посте я опишу три простых техники использования Knockout совместно с SharePoint.&lt;br&gt;
&lt;br&gt;
&lt;a href=&quot;http://omlin.blogspot.com/2014/09/3-knockoutjs-sharepoint.html#more&quot;&gt;Читать дальше »&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://omlin.blogspot.com/feeds/703271534158092638/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://omlin.blogspot.com/2014/09/3-knockoutjs-sharepoint.html#comment-form' title='Комментарии: 6'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/703271534158092638'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/703271534158092638'/><link rel='alternate' type='text/html' href='http://omlin.blogspot.com/2014/09/3-knockoutjs-sharepoint.html' title='3 простых способа подружить KnockoutJs и SharePoint'/><author><name>Andrei</name><uri>http://www.blogger.com/profile/13548051158654215855</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhO_VDIIl7QQb0mB6Ie7sCr0mb_Gu3bKIp6lpEp93R6cPRFwM-qa8lcPV4q_Ghh7yjG1HGRMVpVOW6ale5qCmaA7peNoXdPoKqTRhlF8nBb9fexA9ESq8uZOMgK6ggdaXVqe70qVnZncxg/s72-c/add_button_for_lookup.png" height="72" width="72"/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-70467739252625072.post-1984739902485507597</id><published>2014-08-29T21:42:00.002+04:00</published><updated>2014-08-29T22:15:58.806+04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint2013"/><title type='text'>Поток мыслей: про косячников, внешний мир, и скрытую прелесть Apps</title><content type='html'>Вот не понимаю, как можно в SharePoint&amp;#39;е кого-то называть косячниками? :)&lt;br&gt;
&lt;br&gt;
Ошибка в SharePoint&amp;#39;е может возникнуть абсолютно в любом месте. В самом неожиданном! Самые безобидные действия могут повлечь за собой ужасающие последствия...&lt;br&gt;
&lt;a href=&quot;http://omlin.blogspot.com/2014/08/apps.html#more&quot;&gt;Читать дальше »&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://omlin.blogspot.com/feeds/1984739902485507597/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://omlin.blogspot.com/2014/08/apps.html#comment-form' title='Комментарии: 38'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/1984739902485507597'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/1984739902485507597'/><link rel='alternate' type='text/html' href='http://omlin.blogspot.com/2014/08/apps.html' title='Поток мыслей: про косячников, внешний мир, и скрытую прелесть Apps'/><author><name>Andrei</name><uri>http://www.blogger.com/profile/13548051158654215855</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>38</thr:total></entry><entry><id>tag:blogger.com,1999:blog-70467739252625072.post-91808477426008400</id><published>2014-03-20T09:00:00.000+04:00</published><updated>2014-03-20T09:00:02.752+04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="CSR"/><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint2013"/><title type='text'>Введение в CSR</title><content type='html'>&lt;span style=&quot;font-size: x-small;&quot;&gt;(даже если вы уже смотрели &lt;a href=&quot;http://omlin.blogspot.fi/2013/07/client-side-rendering.html&quot;&gt;доклад&lt;/a&gt;, эта статья все равно может оказаться полезной для вас, т.к. некоторые моменты здесь рассмотрены намного более тщательно, и приводится гораздо больше примеров)&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
CSR - это способ отображения данных в SharePoint 2013, пришедший на смену &lt;a href=&quot;http://omlin.blogspot.fi/2013/08/xslt-rip.html&quot;&gt;скоропостижно скончавшемуся XSLT&lt;/a&gt;. С помощью CSR отображаются и представления списков, и формы списков, и результаты поиска. Хотя бы поэтому нужно знать, что такое CSR и как он работает (о чем, собственно, я и намерен рассказать в этой статье).&lt;br /&gt;
&lt;br /&gt;
Ну и конечно немаловажно, что у CSR есть API, и его можно использовать для создания кастомизаций тех самых представлений списков, их форм, и результатов поиска. И об этом мы тоже поговорим чуть ниже.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Как устроен CSR&lt;/h3&gt;
CSR - это подсистема отображения данных, главным отличием которой является тот факт, что она клиентская, т.е. реализована целиком на JavaScript. Иными словами, на стороне сервера рендерятся только данные в Json-формате, которые затем с помощью неких JavaScript-функций превращаются в HTML и затем этот HTML вставляется в DOM страницы.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2cyp_zdGZtp8Ev7jIhz1s17ICrMVCv3rbPqPIprg_iYCc-EXhe_2qnFYHw6fihqllUW99C6wzzgYM1IuZz46uR3Fxvco4wlxC3_96sw4R3vCOYnpHEdnFBhDyAj8pPXLMLdE6pxg1q2w/s1600/json-to-dom.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2cyp_zdGZtp8Ev7jIhz1s17ICrMVCv3rbPqPIprg_iYCc-EXhe_2qnFYHw6fihqllUW99C6wzzgYM1IuZz46uR3Fxvco4wlxC3_96sw4R3vCOYnpHEdnFBhDyAj8pPXLMLdE6pxg1q2w/s1600/json-to-dom.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Т.о. CSR представляет собой своеобразный конвертер, который принимает входящие данные, и возвращает HTML-строку на основе этих данных.&lt;br /&gt;
&lt;br /&gt;
Для удобства CSR реализован не в виде одной огромной функции, а в виде множества javascript-функций, каждая из которых рендерит свой собственный кусочек HTML. Эти функции как правило вызывают одна другую, и таким образом как бы вложены друг в друга.&lt;br /&gt;
&lt;br /&gt;
Исследовав исходный код CSR в файле /_layouts/15/clienttemplates.debug.js, я составил полную схему, которая демонстрирует порядок вызова этих функций:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXX7cXsFwS5CVRNFJ9qu2wRIrBBrQlYKPNVpuwi13Np8WqRTlMWA_O4Pzk3MR4vn6yZLpduPUKRekVZBkeqIpFoqpJzjFS2cz87nTg6pXh5y1rfiahpn-yfrmkpttQUG3Zx2zUct4jTXc/s1600/templates.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXX7cXsFwS5CVRNFJ9qu2wRIrBBrQlYKPNVpuwi13Np8WqRTlMWA_O4Pzk3MR4vn6yZLpduPUKRekVZBkeqIpFoqpJzjFS2cz87nTg6pXh5y1rfiahpn-yfrmkpttQUG3Zx2zUct4jTXc/s1600/templates.png&quot; height=&quot;233&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
OnPrePrender и OnPostRender отличаются от Render*-функций тем, что являются событиями, срабатывающими соответственно перед процессом генерации HTML и сразу после завершения этого процесса. Эти события служат в основном для расширений, в то время как Render*-функции выполняют основную работу по отображению.&lt;br /&gt;
&lt;br /&gt;
Если взять в качестве примера представление произвольного списка, можно отметить области, которые были срендерены каждой из этих Render*-функций:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdmS0mioLEieY2mYjn1CrUnlQcgg0p55zQtqZxtyWk8enjXUPLavuAbd1jd_g19xOT_E2mnhsKPMQrkuBesWvUQfIRu-i4-76ZGjhrkShAwdtE88yUu9M-mZi81_A1SyG_NpXaqvStirQ/s1600/templates_onlist.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdmS0mioLEieY2mYjn1CrUnlQcgg0p55zQtqZxtyWk8enjXUPLavuAbd1jd_g19xOT_E2mnhsKPMQrkuBesWvUQfIRu-i4-76ZGjhrkShAwdtE88yUu9M-mZi81_A1SyG_NpXaqvStirQ/s1600/templates_onlist.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Ну что же, пока что довольно просто и логично, неправда ли?&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Используем CSR API&lt;/h3&gt;
Есть два основных способа кастомизации CSR:&lt;br /&gt;
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Подписывание на события OnPreRender и OnPostRender&lt;/li&gt;
&lt;li&gt;Подмена (override) функций-шаблонов Render*.&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
Технически оба способа доступны через единое API, а именно через функцию&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;background-color: #cccccc; font-family: Courier New, Courier, monospace;&quot;&gt;SPClientTemplates.TemplateManager.RegisterTemplateOverrides(options)&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Функция RegisterTemplateOverrides принимает в качестве единственного параметра объект, содержащий всю необходимую информацию для кастомизации и имеющий следующую структуру:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;OnPreRender&lt;/li&gt;
&lt;li&gt;Templates&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;View&lt;/li&gt;
&lt;li&gt;Header&lt;/li&gt;
&lt;li&gt;Body&lt;/li&gt;
&lt;li&gt;Footer&lt;/li&gt;
&lt;li&gt;Group&lt;/li&gt;
&lt;li&gt;Item&lt;/li&gt;
&lt;li&gt;Field&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;OnPostRender&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
В полях OnPreRender и OnPostRender можно указать одну функцию или же массив функций. Пример:&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f9f9f9; color: #080808;&quot;&gt;SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
  &lt;span style=&quot;color: #bf4f24;&quot;&gt;OnPreRender&lt;/span&gt;: &lt;span style=&quot;color: #a71d5d; font-style: italic;&quot;&gt;function&lt;/span&gt;() { &lt;span style=&quot;color: #bf4f24;&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;color: #693a17;&quot;&gt;.log&lt;/span&gt;(&lt;span style=&quot;color: #0b6125;&quot;&gt;&#39;CSR OnPreRender&#39;&lt;/span&gt;); },
  &lt;span style=&quot;color: #bf4f24;&quot;&gt;OnPostRender&lt;/span&gt;: [
    &lt;span style=&quot;color: #a71d5d; font-style: italic;&quot;&gt;function&lt;/span&gt;() { &lt;span style=&quot;color: #bf4f24;&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;color: #693a17;&quot;&gt;.log&lt;/span&gt;(&lt;span style=&quot;color: #0b6125;&quot;&gt;&#39;CSR OnPostRender&#39;&lt;/span&gt;); },
    &lt;span style=&quot;color: #a71d5d; font-style: italic;&quot;&gt;function&lt;/span&gt;() { &lt;span style=&quot;color: #693a17;&quot;&gt;alert&lt;/span&gt;(&lt;span style=&quot;color: #0b6125;&quot;&gt;&#39;CSR OnPostRender&#39;&lt;/span&gt;); }
  ]
});
&lt;/pre&gt;
&lt;br /&gt;
Для полей внутри составного поля Templates можно указывать функцию или строку. В случае строки внутри можно использовать токены, ссылающиеся на JavaScript-контекст:&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f9f9f9; color: #080808;&quot;&gt;SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
  Templates: {
    Footer: &lt;span style=&quot;color: #0b6125;&quot;&gt;&quot;Hello world from &amp;lt;#= ctx.ListTitle #&amp;gt;!&quot;&lt;/span&gt;
  }
});
&lt;/pre&gt;
&lt;br /&gt;
Результат работы такой функции будет следующий:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxPxZy9zNWQSMJGse8J8C5Bz6Jf7IqgUH62coHOFrxA-yaj_uGQ9jE9Kvf9YWEu6NZtkB5did9Gm980tNOa_OyCoWpNGwFF_9_TvGwGJPem_Tp6ZpQfMUSko247UXwdIB_0BrTwqD2DxI/s1600/helloworld.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxPxZy9zNWQSMJGse8J8C5Bz6Jf7IqgUH62coHOFrxA-yaj_uGQ9jE9Kvf9YWEu6NZtkB5did9Gm980tNOa_OyCoWpNGwFF_9_TvGwGJPem_Tp6ZpQfMUSko247UXwdIB_0BrTwqD2DxI/s1600/helloworld.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Как видите, в Footer представления списка добавилась наша строка, и токен был заменен значением, соответствующим заголовку списка.&lt;br /&gt;
&lt;br /&gt;
Вместо строки-шаблона можно использовать функцию, вот как это выглядит:&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f9f9f9; color: #080808;&quot;&gt;SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
  Templates: {
    &lt;span style=&quot;color: #bf4f24;&quot;&gt;Footer&lt;/span&gt;: &lt;span style=&quot;color: #a71d5d; font-style: italic;&quot;&gt;function&lt;/span&gt;(ctx) {
      &lt;span style=&quot;color: #794938;&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: #0b6125;&quot;&gt;&quot;Hello world from &quot;&lt;/span&gt; &lt;span style=&quot;color: #794938;&quot;&gt;+&lt;/span&gt; ctx.ListTitle &lt;span style=&quot;color: #794938;&quot;&gt;+&lt;/span&gt; &lt;span style=&quot;color: #0b6125;&quot;&gt;&quot;!&quot;&lt;/span&gt;;
    }
  }
});
&lt;/pre&gt;
&lt;br /&gt;
При генерации HTML-строк в CSR очень удобно использовать функцию String.format, которая автоматически уже есть на любой странице SharePoint&#39;а и позволяет делать то же самое, что серверный C#-овский &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/b1csw23d(v=vs.110).aspx&quot;&gt;String.Format&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f9f9f9; color: #080808;&quot;&gt;SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
  Templates: {
    &lt;span style=&quot;color: #bf4f24;&quot;&gt;Footer&lt;/span&gt;: &lt;span style=&quot;color: #a71d5d; font-style: italic;&quot;&gt;function&lt;/span&gt;(ctx) {
      &lt;span style=&quot;color: #794938;&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: #691c97;&quot;&gt;String&lt;/span&gt;.format(&lt;span style=&quot;color: #0b6125;&quot;&gt;&quot;Hello world from {0}!&quot;&lt;/span&gt;, ctx.ListTitle);
    }
  }
});
&lt;/pre&gt;
&lt;br /&gt;
Обратите внимание, что обработчик должен принимать в качестве параметра объект ctx - это тот самый JSON-объект, который генерируется на стороне сервера. И естественно, возвращает функция обработчика HTML-строку.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style=&quot;color: red;&quot;&gt;Замечание&lt;/span&gt;&lt;/b&gt;: при регистрации override&#39;а, исходный шаблон будет&amp;nbsp;&lt;b&gt;ЗАМЕНЕН&lt;/b&gt;, т.е. больше он вызываться не будет, а вместо него будет запускаться ваш шаблон. Поэтому, если в предыдущем примере заменить Footer на Body, то результат будет такой:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtZYb1L9HT-eA3qPZuGS9o-cDA3jV3DXy_oxMDuJE4_cou_A90XMtW_96qbEoKVcawf2fm7FWTIoX_x_THj5pm9YVrvDCcIfeI0HasveJG1W4nu9F3Cd7qKQRgymyRTLz9zwRaQE-hnfg/s1600/customize_body.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtZYb1L9HT-eA3qPZuGS9o-cDA3jV3DXy_oxMDuJE4_cou_A90XMtW_96qbEoKVcawf2fm7FWTIoX_x_THj5pm9YVrvDCcIfeI0HasveJG1W4nu9F3Cd7qKQRgymyRTLz9zwRaQE-hnfg/s1600/customize_body.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Как видите, записи списка более не отображаются. Т.о. важно понимать, что если вы хотите заменить шаблон не полностью, а только одну малую его часть, вам все равно придется генерировать каким-то образом все остальное.&lt;br /&gt;
&lt;br /&gt;
Чтобы этого избежать, можно попробовать вместо замены шаблона использовать событие OnPostRender, и заменять/дополнять нужный вам элемент с помощью jQuery или селекторов.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Вызов других шаблонов&lt;/h3&gt;
Как я уже упоминал, шаблоны CSR как бы вложены друг в друга, потому что друг друга вызывают. Поскольку вам придется подменять эти шаблоны в процессе кастомизаций, возникает естественный вопрос: а как вызывать низлежащие шаблоны?&lt;br /&gt;
&lt;br /&gt;
Оказывается, когда JSON-объект сгенерированный на стороне сервера начинает использоваться в качестве контекстного объекта в CSR, этот объект дополняется всякими полезными при обработке полями и методами. И в частности, в нем можно найти все Render*-функции:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYZbiwrI4VM9T11uup545pmwwDN8uncvjULqVo5238vRYYlB99hEabJBg0vefiMRkYLZcXRN6eIqsBB5MkBtPTkMs0r56XRTrXTsfvQGKtEHUyIvk9RXUHS1kF70pJrK_CbPsWXbhHlx4/s1600/ctx_render_functions.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYZbiwrI4VM9T11uup545pmwwDN8uncvjULqVo5238vRYYlB99hEabJBg0vefiMRkYLZcXRN6eIqsBB5MkBtPTkMs0r56XRTrXTsfvQGKtEHUyIvk9RXUHS1kF70pJrK_CbPsWXbhHlx4/s1600/ctx_render_functions.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
Таким образом, вызов низлежащих функций не представляет никаких проблем. Пример:&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f9f9f9; color: #080808;&quot;&gt;SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
  Templates: {
    &lt;span style=&quot;color: #bf4f24;&quot;&gt;View&lt;/span&gt;: &lt;span style=&quot;color: #a71d5d; font-style: italic;&quot;&gt;function&lt;/span&gt;(ctx) {
      &lt;span style=&quot;color: #794938;&quot;&gt;return&lt;/span&gt; ctx.RenderHeader() &lt;span style=&quot;color: #794938;&quot;&gt;+&lt;/span&gt; ctx.RenderBody() &lt;span style=&quot;color: #794938;&quot;&gt;+&lt;/span&gt; ctx.RenderFooter();
    }
  }
});
&lt;/pre&gt;
&lt;br /&gt;
&lt;h3&gt;
Подключение к представлению&lt;/h3&gt;
Куда же нужно положить JavaScript-код с вызовом RegisterTemplateOverrides, чтобы кастомизация заработала? Очень просто: нужно положить этот код на страницу сразу после представления списка.&lt;br /&gt;
&lt;br /&gt;
Представленный выше пример я сделал следующим образом: перешел в режим редактирования страницы, добавил веб-часть Script Editor, и добавил туда вышеозначенный код:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjypmjpAAokG0ENZsWvvRTHdjy575d3IhU8PImUrgJS5w4JqPq_TAeK-Pi3gwQeELjhpv7DMImIkrxTJ2wFAJ4b9ajo_CPBPMeT1rAua9qtsHLRbYldV_0ih9qZgi80Je_whEXWB4DaFjQ/s1600/editpage.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjypmjpAAokG0ENZsWvvRTHdjy575d3IhU8PImUrgJS5w4JqPq_TAeK-Pi3gwQeELjhpv7DMImIkrxTJ2wFAJ4b9ajo_CPBPMeT1rAua9qtsHLRbYldV_0ih9qZgi80Je_whEXWB4DaFjQ/s1600/editpage.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
Чтобы код работал из любого места страницы, необходимо обернуть его в широко известный SP.SOD.executeFunc:&lt;br /&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f9f9f9; color: #080808;&quot;&gt;SP.SOD.executeFunc(&lt;span style=&quot;color: #0b6125;&quot;&gt;&quot;clienttemplates.js&quot;&lt;/span&gt;, &lt;span style=&quot;color: #0b6125;&quot;&gt;&quot;SPClientTemplates&quot;&lt;/span&gt;, &lt;span style=&quot;color: #a71d5d; font-style: italic;&quot;&gt;function&lt;/span&gt;() {

  SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
    &lt;span style=&quot;color: #5a525f; font-style: italic;&quot;&gt;// ...&lt;/span&gt;
  });

});

&lt;/pre&gt;
&lt;br /&gt;
В этом случае можно подключать хоть в header, и делать это любым способом (через masterpage, через page layout, через script link и т.п.) - все сработает нормально.&lt;br /&gt;
&lt;br /&gt;
Теперь давайте посмотрим, как сделать так, чтобы кастомизировался только нужный нам view (если на странице несколько view разных списков). Для этого в объекте опций предусмотрены 3 дополнительных поля: ViewStyle, ListTemplateType и BaseViewID.&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;ListTemplateType &lt;/b&gt;- номер шаблона списка (&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.client.listtemplatetype&quot;&gt;перечисление ListTemplateType&lt;/a&gt;). Например, для того, чтобы наш шаблон срабатывал только на списки типа &quot;Задачи&quot; (&quot;Tasks&quot;), нужно указать ListTemplateType=171:&lt;br /&gt;&lt;br /&gt;
&lt;pre style=&quot;background: #f9f9f9; color: #080808;&quot;&gt;SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
  Templates: {
    &lt;span style=&quot;color: #bf4f24;&quot;&gt;Footer&lt;/span&gt;: &lt;span style=&quot;color: #a71d5d; font-style: italic;&quot;&gt;function&lt;/span&gt;(ctx) {
      &lt;span style=&quot;color: #794938;&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: #691c97;&quot;&gt;String&lt;/span&gt;.format(&lt;span style=&quot;color: #0b6125;&quot;&gt;&quot;Hello world from {0}!&quot;&lt;/span&gt;, ctx.ListTitle);
    }
  },
  ListTemplateType: &lt;span style=&quot;color: #811f24; font-weight: 700;&quot;&gt;171&lt;/span&gt;
});
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ViewStyle &lt;/b&gt;- тип представления. Имеет смысл указывать один из существующих типов представления, который можно задать в настройках любого представления списка в SharePoint:&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZeiEr9H5na4pE4_bFW76iLtrguutqE0lMOcYxQhwoVKw1tE3zI9AC-BIkHQHI9rOd6xSJNzcp5IqxFT0117_iU-IjJDyO252OqBYko7im5DzUG8KXpJB8nCVTOXlC_IZXd5pjVtJFgO8/s1600/viewstyle.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZeiEr9H5na4pE4_bFW76iLtrguutqE0lMOcYxQhwoVKw1tE3zI9AC-BIkHQHI9rOd6xSJNzcp5IqxFT0117_iU-IjJDyO252OqBYko7im5DzUG8KXpJB8nCVTOXlC_IZXd5pjVtJFgO8/s1600/viewstyle.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
ID для этих ViewStyle можно легко выдрать из того самого select&#39;а на странице настроек представления:
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzCQ8kdBjQAG_oCQRa-RiDUuK46BRvxFurZXEFeDZX3G9k_zYzkqV67UFesLPjswkNvf57yxIIAy8BdiszM9husBH2N3cxJRETN8DhB3Vs0xd3G4yxDXI1z9ipXCQXdE7QFVbvM0PO_tg/s1600/viewstyle_ids.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzCQ8kdBjQAG_oCQRa-RiDUuK46BRvxFurZXEFeDZX3G9k_zYzkqV67UFesLPjswkNvf57yxIIAy8BdiszM9husBH2N3cxJRETN8DhB3Vs0xd3G4yxDXI1z9ipXCQXdE7QFVbvM0PO_tg/s1600/viewstyle_ids.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;BaseViewID &lt;/b&gt;- это значение свойства BaseViewID у View, его можно подсмотреть в PowerShell или в SharePoint Designer.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
Используя эти три поля, можно &quot;нацелить&quot; кастомизацию строго на нужный список, чтобы никакие другие списки на странице не были затронуты.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Про JSLink&lt;/h3&gt;
Я с удивлением замечаю, что JSLink для многих является практически синонимом CSR. Многие статьи про CSR имеют заголовок из серии &quot;Новая фича шарепойнта - JSLink&quot;, и дальше повествование идет о CSR... Я считаю своим долгом рассеять эти заблуждения.&lt;br /&gt;
&lt;br /&gt;
Правда заключается в том, что JSLink не имеет никакого отношения к CSR вообще. Они &lt;b&gt;не связаны&lt;/b&gt;. Они могут использоваться вместе, но это совершенно необязательно. CSR прекрасно работает без всяких JSLink, как мы видели выше. А JSLink прекрасно работает без CSR-скриптов.&lt;br /&gt;
&lt;br /&gt;
JSLink - это просто способ прицепить некий javascript к некоему объекту SharePoint. Свойство JSLink присутствует у многих объектов SharePoint:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;SPContentType&lt;/li&gt;
&lt;li&gt;SPField&lt;/li&gt;
&lt;li&gt;SPForm (кстати, по непонятным причинам, мне не удалось заставить работать именно SPForm.JSLink, хотя согласно моим исследованиям через dotPeek, все должно прекрасно работать - не знаю в чем было дело, может быть у вас получится?...)&lt;/li&gt;
&lt;li&gt;SPView&lt;/li&gt;
&lt;li&gt;XsltListViewWebPart&lt;/li&gt;
&lt;li&gt;ListFormWebPart&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
Как только мы проставляем это свойство у некоего объекта SharePoint, везде где он появляется на портале, везде будут добавлены соответствующие js-файлы.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Фактически эти js-файлы добавляются через контрол ScriptLink, что кстати говоря гарантирует автоматическое решение проблемы дубликатов - если кто не знал, контрол ScriptLink не позволяет загрузить на страницу дважды файл с одинаковым путем. Т.е. если поместить 2 ScriptLink-контрола на одну страницу и в обоих прописать один и тот же файл, то будет загружен лишь один файл (но сильно не обольщайтесь, дубликаты отслеживаются только по url, а не по контенту).&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Внутри свойства JSLink можно использовать некоторые токены и особый синтаксис:&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;Во-первых, можно загружать несколько файлов сразу, используя в качестве разделителя вертикальную черту (&quot;|&quot;).&lt;/li&gt;
&lt;li&gt;Во-вторых, можно использовать токены &quot;~site&quot; и &quot;~sitecollection&quot;, которые будут заменены на соответствующие URL.&lt;/li&gt;
&lt;li&gt;В-третьих, можно использовать &quot;(d)&quot; на конце, чтобы грузить файлы в режиме SOD (Script-On-Demand). Т.е. вместо того, чтобы быть загруженным на страницу сразу, скрипт будет зарегистрирован в SOD системе и будет действительно загружен только в том случае, если кто-то к нему обратиться, используя &quot;SP.SOD.executeFunc&quot; или подобный метод. Внимание! Только скрипты, поддерживающие SOD, могут быть загружены таким способом.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
В общем, JSLink - это очень удобный способ загрузки скриптов в SharePoint&#39;е, и безусловно этот способ можно и нужно использовать вместе с CSR. Однако, важно понимать, что JSLink никак не влияет на CSR, и например можно подцепить CSR-скрипт к объекту списка А, и этим скриптом применять кастомизации к совершенно другому списку В....&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Также, надеюсь понятно, что через CSR можно грузить далеко не только CSR-скрипты, но и любые сторонние файлы - например, jQuery, knockout.js и т.п.&lt;/div&gt;
&lt;/div&gt;
&lt;h3&gt;
Заключение&lt;/h3&gt;
&lt;/div&gt;
&lt;div&gt;
На мой взгляд CSR - это отличная замена XSLT. Огромным преимуществом CSR является то, что CSR базируется на JavaScript. Сейчас столько всего происходит вокруг JavaScript! Буквально каждую неделю появляются какие-нибудь новые классные библиотеки и фреймворки, создаются инструменты, и т.д. Мне кажется, CSR - это отличный шанс привнести современные достижения web-технологий в SharePoint, и начать создавать по-настоящему удобные и качественные решения.&lt;br /&gt;
&lt;br /&gt;
Конечно, как и везде в SharePoint, у CSR есть свои тараканы, и следует быть крайне осторожными в оценке трудозатрат, особенно если вы пока еще мало работали с CSR.&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://omlin.blogspot.com/feeds/91808477426008400/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://omlin.blogspot.com/2014/03/csr.html#comment-form' title='Комментарии: 34'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/91808477426008400'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/91808477426008400'/><link rel='alternate' type='text/html' href='http://omlin.blogspot.com/2014/03/csr.html' title='Введение в CSR'/><author><name>Andrei</name><uri>http://www.blogger.com/profile/13548051158654215855</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2cyp_zdGZtp8Ev7jIhz1s17ICrMVCv3rbPqPIprg_iYCc-EXhe_2qnFYHw6fihqllUW99C6wzzgYM1IuZz46uR3Fxvco4wlxC3_96sw4R3vCOYnpHEdnFBhDyAj8pPXLMLdE6pxg1q2w/s72-c/json-to-dom.png" height="72" width="72"/><thr:total>34</thr:total></entry><entry><id>tag:blogger.com,1999:blog-70467739252625072.post-2173320199005016059</id><published>2014-03-19T09:00:00.000+04:00</published><updated>2014-03-19T09:00:09.606+04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint2010"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint2013"/><title type='text'>Web scraping с помощью XmlWebPart</title><content type='html'>Хочу поделиться небольшой находкой, обнаруженной мной буквально на днях: как делать web scraping без серверного кода (и соответственно это вообще единственный известный мне способ делать web scraping в Office365).&lt;br&gt;
&lt;br&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiA-wdWa0iMuRq3eVOf3uYIuv6XeoroXz09k31l96I7bf15B4LUcGmQc39PBwXM4F64GoeMKDhA7OJtLMbD8ioxNfh6ao2wAm2uR1oAIctsmbMs-bQFInIJMIuKbrUsrTq6O-PokqEAaWo/s1600/scraper.jpg&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiA-wdWa0iMuRq3eVOf3uYIuv6XeoroXz09k31l96I7bf15B4LUcGmQc39PBwXM4F64GoeMKDhA7OJtLMbD8ioxNfh6ao2wAm2uR1oAIctsmbMs-bQFInIJMIuKbrUsrTq6O-PokqEAaWo/s1600/scraper.jpg&quot;&gt;&lt;/a&gt;&lt;/div&gt;
На всякий случай, Web scraping - это способ интеграции с внешним ресурсом, при котором нужная информация выпарзивается прямо из HTML-кода некой внешней страницы в интернете. Обычно такое требуется, когда внешний сайт не предоставляет нормального API и нет никакой возможности его сделать (на самом деле, по моему опыту, такие ситуации возникают постоянно).&lt;br&gt;
&lt;br&gt;
Безусловно это ужасный способ интеграции, хрупкий и ненадежный, и я искренне надеюсь, что он вам никогда не понадобится. Но если все-таки такое случится, то оказывается иногда это можно сделать даже без серверного кода.&lt;br&gt;
&lt;br&gt;
&lt;a href=&quot;http://omlin.blogspot.com/2014/03/web-scraping-xmlwebpart.html#more&quot;&gt;Читать дальше »&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://omlin.blogspot.com/feeds/2173320199005016059/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://omlin.blogspot.com/2014/03/web-scraping-xmlwebpart.html#comment-form' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/2173320199005016059'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/2173320199005016059'/><link rel='alternate' type='text/html' href='http://omlin.blogspot.com/2014/03/web-scraping-xmlwebpart.html' title='Web scraping с помощью XmlWebPart'/><author><name>Andrei</name><uri>http://www.blogger.com/profile/13548051158654215855</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiA-wdWa0iMuRq3eVOf3uYIuv6XeoroXz09k31l96I7bf15B4LUcGmQc39PBwXM4F64GoeMKDhA7OJtLMbD8ioxNfh6ao2wAm2uR1oAIctsmbMs-bQFInIJMIuKbrUsrTq6O-PokqEAaWo/s72-c/scraper.jpg" height="72" width="72"/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-70467739252625072.post-4709234134241941312</id><published>2014-03-16T09:00:00.000+04:00</published><updated>2014-03-17T13:22:49.197+04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint2013"/><category scheme="http://www.blogger.com/atom/ns#" term="SPList"/><title type='text'>Отображение подчиненных списков в SharePoint</title><content type='html'>Довольно часто возникает ситуация, когда клиенты просят создать некую форму (или как это у них модно называть &quot;карточку&quot; бизнес-объекта), на которой в числе прочего должны отображаться элементы связанных (подчиненных) списков.&lt;br /&gt;
&lt;br /&gt;
В качестве банального примера здесь можно привести форму заказа, где присутствует общая информация о заказе, и плюс список позиций заказа. В интранетах встречается множество вариаций этой задачи, порой довольно специфичных, но я буду использовать именно форму заказа в качестве примера в этой статье, поскольку она всем понятна и ее легко объяснить.&lt;br /&gt;
&lt;br /&gt;
С технической точки зрения, в этой статье я продемонстрирую использование OOTB веб-частей и их связывание друг с другом и с внешними параметрами. Также в процессе создания решения я буду использовать CSR и даже кастомизировать JSGrid.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Варианты решения&lt;/h3&gt;
Как известно, в InfoPath специально для отображения подчиненных списков уже есть готовый инструмент, и вроде бы чего тут вообще изобретать велосипед!? Однако, с InfoPath обычно возникает слишком много проблем (подробнее можно почитать &lt;a href=&quot;http://omlin.blogspot.fi/2013/03/sharepoint-list-forms-2013.html&quot;&gt;в моей статье про формы списков в SharePoint 2013&lt;/a&gt;), да и вообще &lt;a href=&quot;http://blogs.office.com/2014/01/31/update-on-infopath-and-sharepoint-forms/&quot;&gt;InfoPath уже официально &quot;заканчивается&quot;&lt;/a&gt;, если вдруг кто не в курсе. Но если не InfoPath, то что?&lt;br /&gt;
&lt;br /&gt;
На самом деле задача решается достаточно легко средствами SharePoint, без всяких InfoPath и даже без кода. И вариантов решения даже не один, а довольно много. Например, в некоторых случаях можно использовать Document Set&#39;ы, а &lt;a href=&quot;http://gandjustas.blogspot.com/&quot;&gt;Стас Выщепан&lt;/a&gt; придумал, что можно банально сделать библиотеку с оформленными по шаблону Excel-документами.&lt;br /&gt;
&lt;br /&gt;
Что до меня, я обычно использую вот какой способ:&lt;br /&gt;
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Создается отдельный page layout.&lt;/li&gt;
&lt;li&gt;Создается отдельный список &quot;позиций&quot;, с lookup-полем, ссылающимся на библиотеку документов настроенную на упомянутый выше page layout.&lt;/li&gt;
&lt;li&gt;На page layout добавляются поля заказа, а также вебчасть CQWP, ссылающаяся на список позиций,&amp;nbsp;с фильтром по вышеупомянутому lookup-полю.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhCBWFbE2Ooag1ooQs7Rh6aC_Z4-NtuHSDCNG_kYanZF2fSh21T1tKueE10FReZDQ_rkv0tUQu3mlhuzqYLibT3514JDeOU5gcqarPiP3xtSiIPa_-uIed60Rgn_cUgGZ-gmksQO_3uoto/s1600/solution_schema.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhCBWFbE2Ooag1ooQs7Rh6aC_Z4-NtuHSDCNG_kYanZF2fSh21T1tKueE10FReZDQ_rkv0tUQu3mlhuzqYLibT3514JDeOU5gcqarPiP3xtSiIPa_-uIed60Rgn_cUgGZ-gmksQO_3uoto/s1600/solution_schema.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
Даже в изначальном виде этот способ отлично работает, хорошо интегрирован в SharePoint, визуален, пригоден для печати (ну, возможно придется добавить пару стилей CSS для @media print).&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Главным недостатком этого варианта я считаю печально известное ограничение на максимум в 5000 записей в списке позиций, что автоматически еще больше ограничивает максимум записей в основной библиотеке документов. Если вы захотите использовать предложенный мной способ, обязательно определите ориентировочную быстроту наполнения списка позиций, задокументируйте это число и известите об этом клиента, и если потребуется, подумайте о своевременной архивации этого списка.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3&gt;
По шагам&lt;/h3&gt;
&lt;div&gt;
Как известно, в SharePoint&#39;е можно застопориться на день-другой на любой даже самой простейшей ерунде, поэтому на мой взгляд, описание реализации по шагам всегда должно присутствовать в статьях про SharePoint :)&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Поехали:&lt;/div&gt;
&lt;br /&gt;
&lt;div&gt;
&lt;ol&gt;
&lt;li&gt;Site Settings -&amp;gt; Master pages and page layouts -&amp;gt; Ribbon -&amp;gt; New document -&amp;gt; Page layout&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzupfuV_rMuuu7SAJ4aZuBhPz-jYxj3Xc8cJtp1ZafDnk_xVR8N2OQn5OjtXiVgnIYVw7Kg3SMNbMjZH3k0AoX1bQx5gy8CkS9bgjb9MfZO7kP7c8MwlMnILAW-O-rxyd2EYTR1qGvC3E/s1600/create_page_layout.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzupfuV_rMuuu7SAJ4aZuBhPz-jYxj3Xc8cJtp1ZafDnk_xVR8N2OQn5OjtXiVgnIYVw7Kg3SMNbMjZH3k0AoX1bQx5gy8CkS9bgjb9MfZO7kP7c8MwlMnILAW-O-rxyd2EYTR1qGvC3E/s1600/create_page_layout.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;Создаем тип содержимого. Используем ссылку &quot;Create new content type&quot;; выбираем Parent Content Type = Article Page (из группы Page Layout Content Types), задаем имя, OK.&lt;/li&gt;
&lt;li&gt;Далее нужно скрыть ненужные поля и добавить те поля, которые вам нужны. Будьте аккуратны с такими полями как например поля типов Publishing HTML и Publishing Image. Они обязательно должны добавляться именно на этом шаге, т.е. через Content Type, а не непосредственно в библиотеку документов, иначе возможны проблемы.&lt;/li&gt;
&lt;li&gt;Как только тип содержимого создан, возвращаемся к созданию Page layout, обновляем список типов содержимого, выбираем только что созданный, выбираем название для Page layout, OK -&amp;gt; page layout создан!&lt;/li&gt;
&lt;li&gt;Создаем отдельный publishing сайт&lt;/li&gt;
&lt;li&gt;Конфигурируем этот сайт на использование вновь созданного page layout&#39;а (Site settings -&amp;gt; Page layouts and site templates -&amp;gt; Page layouts -&amp;gt; Pages in this site can only use the following layouts -&amp;gt; выбираем только наш layout):&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIdwi6E3iiRt0BpgrK_exRIVe1EU2uuAU-6rriH9jdglQJt7VurCag9va2poxKHLfRMPTnfgDRi_4zH-sg5Bv93yjn2g8RfTpavaLhNUmcz1phgrNoVhJggnHQqy266xmxailz9uAyt98/s1600/pagelayouts_onlyorder.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIdwi6E3iiRt0BpgrK_exRIVe1EU2uuAU-6rriH9jdglQJt7VurCag9va2poxKHLfRMPTnfgDRi_4zH-sg5Bv93yjn2g8RfTpavaLhNUmcz1phgrNoVhJggnHQqy266xmxailz9uAyt98/s1600/pagelayouts_onlyorder.png&quot; /&gt;&lt;/a&gt;&lt;span style=&quot;text-align: left;&quot;&gt;Также выставляем page layout по умолчанию в то же значение, и сохраняем настройки.&lt;/span&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;Теперь создаем список товаров и список позиций на этом самом отдельном сайте. Надеюсь понятно, почему списка 2:&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;список товаров включает в себя все возможные товары&lt;/li&gt;
&lt;li&gt;список позиций содержит ссылки на те товары, которые были выбраны пользователем в заказ. Т.е. по сути дела список позиций это агрегированная таблица, реализующая связь много-ко-многим, и включающая в минимальном варианте 2 колонки: товар и заказ. Чаще всего там также будут дополнительные данные: например, из таблицы товаров может быть подтянута картинка товара, а также не помешает поле с количеством товаров для заказа. Также логично для списка позиций выбрать настройку &quot;отображать только созданные мной записи&quot;, и добавить группировку по заказу. Наконец, не забудьте пожалуйста поле Title скрыть (через тип содержимого), и плюс сделать его не обязательным (в настройках поля).&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;Списки созданы - давайте займемся донастройкой page layout&#39;а. Открываем SharePoint Designer, переходим на нашу коллекцию сайтов, Files-&amp;gt;_catalogs-&amp;gt;masterpage-&amp;gt; ищем вновь созданный page layout, и выбираем Edit file in Advanced Mode через контекстное меню.&lt;/li&gt;
&lt;li&gt;Добавляем обычные поля из типа содержимого. Это кстати можно сделать через SharePoint Designer UI: на Ribbon, есть вкладка Insert, и там эти поля можно найти в раскрывающейся кнопке &quot;SharePoint&quot; - правда иногда приходится немного подождать, т.к. список полей загружается какое-то время, и доступен не сразу.&lt;/li&gt;
&lt;li&gt;Далее добавляем собственно самую интересную часть: список позиций. Тут есть два варианта реализации:&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;Наиболее простой способ это сделать - это использовать CQWP (Content by Query WebPart), как я упоминал выше.&amp;nbsp;Эта веб-часть не имеет возможности редактирования, но зато списки товаров и позиций могут располагаться на любом сайте в текущей сайт-коллекции, что очень удобно.&lt;/li&gt;
&lt;li&gt;Чтобы сделать более user-friendly интерфейс и обеспечить редактирование &quot;на лету&quot;, можно использовать XLV (XsltListViewWebPart). В этом случае списки товаров и позиций должны располагаться на том же сайте, где расположена библиотека документов, настроенная на использование нашего page layout&#39;а. Этот вариант технически сложнее (но и интереснее).&lt;/li&gt;
&lt;/ul&gt;
&lt;/ol&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3&gt;
Список позиций через Content Query Web Part&lt;/h3&gt;
&lt;div&gt;
Последовательность действий в этом случае следующая:&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;На любой webpart page временно добавляем CQWP. Например можно добавить на форму создания элемента любого списка&lt;/li&gt;
&lt;li&gt;Настраиваем CQWP на список позиций.&lt;/li&gt;
&lt;li&gt;Добавляем фильтр по полю из списка позиций, которое указывает на заказ (например, у меня это поле называется Order). Обычно я делаю так, что lookup-поле &quot;Order&quot; ссылается на Title страницы, но в настройках этого поля отмечаю также колонку ID (при этом автоматически добавляется Dependent lookup поле &quot;Order:ID&quot;):
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhW7LpaLdrPuMT2BjrmFVaaY6AvkYojzZQgRABF2pq8KHju8J1Tya2LZpaDIUDKnrEU2bXRAqeR3f8-LG5bj211ktdt9zvNqEawJTZrT0Q2lpXVRIB8bvkcuEEj7D4axeuk-qndXvXwy24/s1600/order_title_and_id.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em; text-align: center;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhW7LpaLdrPuMT2BjrmFVaaY6AvkYojzZQgRABF2pq8KHju8J1Tya2LZpaDIUDKnrEU2bXRAqeR3f8-LG5bj211ktdt9zvNqEawJTZrT0Q2lpXVRIB8bvkcuEEj7D4axeuk-qndXvXwy24/s1600/order_title_and_id.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
И тогда фильтр нужно применять уже именно на поле &quot;Order:ID&quot;.&amp;nbsp;В качестве значения фильтра необходимо указать строку &quot;[PageFieldValue:ID]&quot;.
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgth3xYPgHcR5QFw_rAhDEiB0VdUm8GFLkqUbq0ojKVjUS4UgV3-TWuCQ1P9Zgfmd05GyXUc_JRFA12J6ky_rEzXuo0DmLvz82PH22PBv5iLy_d9lIx-Dm95RD06Iy57q3pbnYpHxYNZAs/s1600/cqwp_filter.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgth3xYPgHcR5QFw_rAhDEiB0VdUm8GFLkqUbq0ojKVjUS4UgV3-TWuCQ1P9Zgfmd05GyXUc_JRFA12J6ky_rEzXuo0DmLvz82PH22PBv5iLy_d9lIx-Dm95RD06Iy57q3pbnYpHxYNZAs/s1600/cqwp_filter.png&quot; /&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
При необходимости изменения способа отображения списка, добавляем стиль в ItemStyle.xsl, и соответственным образом меняем настройки CQWP.&lt;br /&gt;Подсматриваем markup получившейся CQWP из SharePoint Designer, и&amp;nbsp;copy+paste этот маркап в page layout. Обычно нужно скопировать тег&amp;nbsp;&lt;b&gt;WpNs0:ContentByQueryWebPart&lt;/b&gt; и регистрацию соответствующего префикса, т.е. код&amp;nbsp;&lt;span style=&quot;background-color: #cccccc; font-family: Courier New, Courier, monospace;&quot;&gt;&amp;lt;%@ Register TagPrefix=&quot;WpNs0&quot; ... %&amp;gt;&lt;/span&gt;.&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;Для упрощения редактирования, просто добавьте ссылку&amp;nbsp;(target=&quot;_blank&quot;)&amp;nbsp;на список перед этой вебчастью, обернув ее в EditModePanel. Практика показывает, что клиенты в большинстве случаев вполне спокойно относятся к такому варианту редактирования, особенно если функционал редактирования доступен ограниченному числу лиц.&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3&gt;
Список позиций через Xslt List View Web Part&lt;/h3&gt;
&lt;/div&gt;
&lt;div&gt;
Для реализации этого варианта потребуется немного больше знаний и немного больше ручных действий:&lt;/div&gt;
&lt;div&gt;
&lt;ol&gt;
&lt;li&gt;Во-первых, перейдите в SharePoint Designer, на отдельный сайт который вы создали, и найдите файл Lists/ваш_список/AllItems.aspx. Перейдите к редактированию этого файла и выкопируйте оттуда тег XsltListViewWebPart, а также соответствующий ему серверный Register-тег для TagPrefix=&quot;WebPartPages&quot;. Скопированную разметку добавьте на page layout.&lt;/li&gt;
&lt;li&gt;Если сейчас вы посмотрите, как выглядит страница созданная на основе нашего page layout&#39;а, там вы увидите представление списка. Наша задача сделать так, чтобы в режиме редактирования XLV автоматически переходил в режим Quick Edit, а в режиме просмотра выглядел примерно как CQWP. Это делается довольно просто.&lt;/li&gt;
&lt;li&gt;Сначала добавьте код для режима редактирования (нужный код я банально вытащил из onclick атрибута стандартной ссылки &quot;edit this list&quot;):
&lt;pre style=&quot;background: #f9f9f9; color: #080808;&quot;&gt;&amp;lt;&lt;span style=&quot;color: #bf4f24;&quot;&gt;PublishingWebControls:EditModePanel&lt;/span&gt; &lt;span style=&quot;color: #bf4f24;&quot;&gt;runat&lt;/span&gt;=&lt;span style=&quot;color: #0b6125;&quot;&gt;&quot;server&quot;&lt;/span&gt;&amp;gt;
    &amp;lt;&lt;span style=&quot;color: #bf4f24;&quot;&gt;script&lt;/span&gt; &lt;span style=&quot;color: #bf4f24;&quot;&gt;type&lt;/span&gt;=&lt;span style=&quot;color: #0b6125;&quot;&gt;&quot;text/javascript&quot;&lt;/span&gt;&amp;gt;
        _spBodyOnLoadFunctions.&lt;span style=&quot;color: #693a17;&quot;&gt;push&lt;/span&gt;(&lt;span style=&quot;color: #a71d5d; font-style: italic;&quot;&gt;function&lt;/span&gt;()
        {
            EnsureScriptParams(&lt;span style=&quot;color: #0b6125;&quot;&gt;&#39;inplview&#39;&lt;/span&gt;, &lt;span style=&quot;color: #0b6125;&quot;&gt;&#39;InitGridFromView&#39;&lt;/span&gt;, &lt;span style=&quot;color: #0b6125;&quot;&gt;&#39;{YOUR-GUID-HERE}&#39;&lt;/span&gt;);
        });
    &amp;lt;/&lt;span style=&quot;color: #bf4f24;&quot;&gt;script&lt;/span&gt;&amp;gt;
&amp;lt;/&lt;span style=&quot;color: #bf4f24;&quot;&gt;PublishingWebControls:EditModePanel&lt;/span&gt;&amp;gt;
&lt;/pre&gt;
Этот код необходимо поместить сразу после XsltListViewWebPart. GUID берется из View Name:&amp;nbsp;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqCmh1WVWcewaVNoNyETzVZPDGE9nUiBSktPfjz7WeXqqt5G81NLj9EJDKLnmgheBnlI-PJi-7p8EDZnPzLzQAXhib2KeS8riR9zm-LgjY9BLKpzDboGF8zIrPl1KE6PRuFub92XAN4EY/s1600/guid_for_script.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqCmh1WVWcewaVNoNyETzVZPDGE9nUiBSktPfjz7WeXqqt5G81NLj9EJDKLnmgheBnlI-PJi-7p8EDZnPzLzQAXhib2KeS8riR9zm-LgjY9BLKpzDboGF8zIrPl1KE6PRuFub92XAN4EY/s1600/guid_for_script.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;Теперь нужно добавить CSR-преобразование, которое бы изменяло внешний вид списка. В простейшем случае это преобразование будет выглядеть следующим образом:
&lt;pre style=&quot;background: #f9f9f9; color: #080808;&quot;&gt;&amp;lt;&lt;span style=&quot;color: #bf4f24;&quot;&gt;PublishingWebControls:EditModePanel&lt;/span&gt; &lt;span style=&quot;color: #bf4f24;&quot;&gt;runat&lt;/span&gt;=&lt;span style=&quot;color: #0b6125;&quot;&gt;&quot;server&quot;&lt;/span&gt; &lt;span style=&quot;color: #bf4f24;&quot;&gt;PageDisplayMode&lt;/span&gt;=&lt;span style=&quot;color: #0b6125;&quot;&gt;&quot;Display&quot;&lt;/span&gt; &lt;span style=&quot;color: #bf4f24;&quot;&gt;SupressTag&lt;/span&gt;=&lt;span style=&quot;color: #0b6125;&quot;&gt;&quot;True&quot;&lt;/span&gt;&amp;gt;
    &amp;lt;&lt;span style=&quot;color: #bf4f24;&quot;&gt;script&lt;/span&gt; &lt;span style=&quot;color: #bf4f24;&quot;&gt;type&lt;/span&gt;=&lt;span style=&quot;color: #0b6125;&quot;&gt;&quot;text/javascript&quot;&lt;/span&gt;&amp;gt;
       SP.SOD.executeFunc(&lt;span style=&quot;color: #0b6125;&quot;&gt;&#39;clienttemplates.js&#39;&lt;/span&gt;, &lt;span style=&quot;color: #0b6125;&quot;&gt;&#39;SPClientTemplates.TemplateManager&#39;&lt;/span&gt;, &lt;span style=&quot;color: #a71d5d; font-style: italic;&quot;&gt;function&lt;/span&gt;() {
            SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
                Templates: {
                    &lt;span style=&quot;color: #bf4f24;&quot;&gt;View&lt;/span&gt;: &lt;span style=&quot;color: #a71d5d; font-style: italic;&quot;&gt;function&lt;/span&gt; (ctx) {
                        &lt;span style=&quot;color: #794938;&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: #691c97;&quot;&gt;String&lt;/span&gt;.format(&lt;span style=&quot;color: #0b6125;&quot;&gt;&#39;&amp;lt;div class=&quot;cbq-layout-main&quot;&amp;gt;&amp;lt;ul class=&quot;dfwp-list dfwp-column&quot;&amp;gt;{0}&amp;lt;/ul&amp;gt;&amp;lt;/div&amp;gt;&#39;&lt;/span&gt;, ctx.RenderBody(ctx)); 
                    },
                    &lt;span style=&quot;color: #bf4f24;&quot;&gt;Item&lt;/span&gt;: &lt;span style=&quot;color: #a71d5d; font-style: italic;&quot;&gt;function&lt;/span&gt; (ctx) {
                        &lt;span style=&quot;color: #794938;&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: #691c97;&quot;&gt;String&lt;/span&gt;.format(&lt;span style=&quot;color: #0b6125;&quot;&gt;&#39;&amp;lt;li class=&quot;dfwp-item&quot;&amp;gt;&amp;lt;div class=&quot;item&quot;&amp;gt;&amp;lt;div class=&quot;link-item&quot;&amp;gt;{0}&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&#39;&lt;/span&gt;, ctx.CurrentItem[&quot;Item&quot;][0].lookupValue);
                    }
                }
            })
       })
    &amp;lt;/&lt;span style=&quot;color: #bf4f24;&quot;&gt;script&lt;/span&gt;&amp;gt;
&amp;lt;/&lt;span style=&quot;color: #bf4f24;&quot;&gt;PublishingWebControls:EditModePanel&lt;/span&gt;&amp;gt;

&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;Теперь необходимо добавить фильтр по полю Order. Для этого, нужно сделать следующее:
&lt;ul&gt;
&lt;li&gt;сначала нужно добавить в page layout контрол NumberField, ссылающийся на ID текущей страницы, который не будет отображаться, но значение из которого мы будем через ParameterBinding передавать в XLV:&lt;br /&gt;
&lt;pre style=&quot;background: rgb(249, 249, 249);&quot;&gt;&lt;span style=&quot;color: #080808;&quot;&gt;&amp;lt;&lt;span style=&quot;color: #bf4f24;&quot;&gt;div&lt;/span&gt; &lt;span style=&quot;color: #bf4f24;&quot;&gt;style&lt;/span&gt;=&lt;span style=&quot;color: #0b6125;&quot;&gt;&quot;display:none;&quot;&lt;/span&gt;&amp;gt;
   &amp;lt;&lt;span style=&quot;color: #bf4f24;&quot;&gt;SharePointWebControls:NumberField&lt;/span&gt; &lt;span style=&quot;color: #bf4f24;&quot;&gt;ID&lt;/span&gt;=&lt;span style=&quot;color: #0b6125;&quot;&gt;&quot;PageID&quot;&lt;/span&gt; &lt;/span&gt;&lt;span style=&quot;color: #bf4f24;&quot;&gt;ControlMode&lt;/span&gt;&lt;span style=&quot;color: #080808;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #0b6125;&quot;&gt;&quot;Display&quot;&lt;/span&gt; &lt;span style=&quot;color: #bf4f24;&quot;&gt;FieldName&lt;/span&gt;=&lt;span style=&quot;color: #0b6125;&quot;&gt;&quot;1d22ea11-1e32-424e-89ab-9fedbadb6ce1&quot;&lt;/span&gt; &lt;span style=&quot;color: #bf4f24;&quot;&gt;runat&lt;/span&gt;=&lt;span style=&quot;color: #0b6125;&quot;&gt;&quot;server&quot;&lt;/span&gt;/&amp;gt;
&amp;lt;/&lt;span style=&quot;color: #bf4f24;&quot;&gt;div&lt;/span&gt;&amp;gt;
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
Теперь добавляем ParameterBinding (рядом с уже существующими биндингами внутри тега XsltListViewWebPart):
&lt;pre style=&quot;background: #f9f9f9; color: #080808;&quot;&gt;  &amp;lt;&lt;span style=&quot;color: #bf4f24;&quot;&gt;ParameterBinding&lt;/span&gt; &lt;span style=&quot;color: #bf4f24;&quot;&gt;Name&lt;/span&gt;=&lt;span style=&quot;color: #0b6125;&quot;&gt;&quot;pageId&quot;&lt;/span&gt; &lt;span style=&quot;color: #bf4f24;&quot;&gt;Location&lt;/span&gt;=&lt;span style=&quot;color: #0b6125;&quot;&gt;&quot;Control(PageId,ItemFieldValue)&quot;&lt;/span&gt; /&amp;gt;
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
И наконец, собственно настраиваем фильтр, добавляя в тег Query (внутри View) следующий код:
&lt;pre style=&quot;background: #f9f9f9; color: #080808;&quot;&gt;&amp;lt;&lt;span style=&quot;color: #bf4f24;&quot;&gt;Where&lt;/span&gt;&amp;gt;&amp;lt;&lt;span style=&quot;color: #bf4f24;&quot;&gt;Eq&lt;/span&gt;&amp;gt;&amp;lt;&lt;span style=&quot;color: #bf4f24;&quot;&gt;FieldRef&lt;/span&gt; &lt;span style=&quot;color: #bf4f24;&quot;&gt;Name&lt;/span&gt;=&lt;span style=&quot;color: #0b6125;&quot;&gt;&quot;Order&quot;&lt;/span&gt; &lt;span style=&quot;color: #bf4f24;&quot;&gt;LookupId&lt;/span&gt;=&lt;span style=&quot;color: #0b6125;&quot;&gt;&quot;TRUE&quot;&lt;/span&gt; /&amp;gt;&amp;lt;&lt;span style=&quot;color: #bf4f24;&quot;&gt;Value&lt;/span&gt; &lt;span style=&quot;color: #bf4f24;&quot;&gt;Type&lt;/span&gt;=&lt;span style=&quot;color: #0b6125;&quot;&gt;&quot;Integer&quot;&lt;/span&gt;&amp;gt;{pageId}&amp;lt;/&lt;span style=&quot;color: #bf4f24;&quot;&gt;Value&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&quot;color: #bf4f24;&quot;&gt;Eq&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&quot;color: #bf4f24;&quot;&gt;Where&lt;/span&gt;&amp;gt;
&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div&gt;
После выполнения этих действий, в режиме редактирования моя тестовая страница выглядела вот как (из общих полей я добавлял только поле Comments):&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjREfWQN8tA6P8m0Y9qBVkfiftYvEgfXQgOW1h1JV8ZkDpPaTeTPFKBzCd_Um41Pxb9BldSZRKdB2dIM9ub_gnjk7364gMbEKmYuSQO2LrmeXmkAEJHOrLijeAEXVTuxGBexfE7I3qUHkI/s1600/editmode_xlv.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjREfWQN8tA6P8m0Y9qBVkfiftYvEgfXQgOW1h1JV8ZkDpPaTeTPFKBzCd_Um41Pxb9BldSZRKdB2dIM9ub_gnjk7364gMbEKmYuSQO2LrmeXmkAEJHOrLijeAEXVTuxGBexfE7I3qUHkI/s1600/editmode_xlv.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Вроде бы уже здорово, вау, но... на самом деле ничего не работает :)&lt;br /&gt;
&lt;br /&gt;
Точнее, не работает добавление новых записей - добавиться-то они добавятся, но с текущей страницей связаны не будут, и как следствие, если страницу обновить, они с нее пропадут.&lt;br /&gt;
&lt;br /&gt;
Кроме такой вот большой проблемы, есть также и несколько мелких недочетов:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;при попытке сортировки грида выводятся все записи списка, фильтрация по ID страницы слетает&lt;/li&gt;
&lt;li&gt;встроенный в грид функционал по добавлению колонок, а также по их фильтрации - явно лишний.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
Поскольку XLV в режиме редактирования выводится с помощью JSGrid, для исправления этих проблем понадобятся знания по контролу JSGrid. К сожалению, документации по JSGrid в интернете практически нет, а API там очень большой и разобраться самостоятельно - сложно. Но если все-таки это сделать, все наши проблемы решаются буквально парой десятков строк javascript-кода (этот фрагмент необходимо разместить после XLV):&lt;/div&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f9f9f9; color: #080808;&quot;&gt;&amp;lt;&lt;span style=&quot;color: #bf4f24;&quot;&gt;PublishingWebControls:EditModePanel&lt;/span&gt; &lt;span style=&quot;color: #bf4f24;&quot;&gt;runat&lt;/span&gt;=&lt;span style=&quot;color: #0b6125;&quot;&gt;&quot;server&quot;&lt;/span&gt;&amp;gt;
    &amp;lt;&lt;span style=&quot;color: #bf4f24;&quot;&gt;script&lt;/span&gt; &lt;span style=&quot;color: #bf4f24;&quot;&gt;type&lt;/span&gt;=&lt;span style=&quot;color: #0b6125;&quot;&gt;&quot;text/javascript&quot;&lt;/span&gt;&amp;gt;
        _spBodyOnLoadFunctions.&lt;span style=&quot;color: #693a17;&quot;&gt;push&lt;/span&gt;(&lt;span style=&quot;color: #a71d5d; font-style: italic;&quot;&gt;function&lt;/span&gt;()
        {
            &lt;span style=&quot;color: #a71d5d; font-style: italic;&quot;&gt;var&lt;/span&gt; viewId &lt;span style=&quot;color: #794938;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #0b6125;&quot;&gt;&#39;{8571F3CD-C286-4D4D-89AD-D4B2507A9448}&#39;&lt;/span&gt;;
            &lt;span style=&quot;color: #a71d5d; font-style: italic;&quot;&gt;var&lt;/span&gt; orderColumnName &lt;span style=&quot;color: #794938;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #0b6125;&quot;&gt;&#39;Order&#39;&lt;/span&gt;;

            g_SPGridInitInfo[viewId].jsInitObj.canUserAddColumn &lt;span style=&quot;color: #794938;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #811f24; font-weight: 700;&quot;&gt;false&lt;/span&gt;;
            g_SPGridInitInfo[viewId].jsInitObj.showAddColumn &lt;span style=&quot;color: #794938;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #811f24; font-weight: 700;&quot;&gt;false&lt;/span&gt;;
            EnsureScriptParams(&lt;span style=&quot;color: #0b6125;&quot;&gt;&#39;inplview&#39;&lt;/span&gt;, &lt;span style=&quot;color: #0b6125;&quot;&gt;&#39;InitGridFromView&#39;&lt;/span&gt;, viewId);
            
            SP.SOD.executeFunc(&lt;span style=&quot;color: #0b6125;&quot;&gt;&#39;spgantt.js&#39;&lt;/span&gt;, &lt;span style=&quot;color: #0b6125;&quot;&gt;&#39;SP.GanttControl&#39;&lt;/span&gt;, &lt;span style=&quot;color: #a71d5d; font-style: italic;&quot;&gt;function&lt;/span&gt;() {
                &lt;span style=&quot;color: #a71d5d; font-style: italic;&quot;&gt;var&lt;/span&gt; jsGridContainer &lt;span style=&quot;color: #794938;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #794938;&quot;&gt;$&lt;/span&gt;get(&lt;span style=&quot;color: #0b6125;&quot;&gt;&quot;spgridcontainer_&quot;&lt;/span&gt; &lt;span style=&quot;color: #794938;&quot;&gt;+&lt;/span&gt; g_SPGridInitInfo[viewId].jsInitObj.qualifier);
                jsGridContainer.jsgrid.HideColumn(orderColumnName);
                &lt;span style=&quot;color: #a71d5d; font-style: italic;&quot;&gt;var&lt;/span&gt; columns &lt;span style=&quot;color: #794938;&quot;&gt;=&lt;/span&gt; jsGridContainer.jsgrid.GetColumns();
                &lt;span style=&quot;color: #794938;&quot;&gt;for&lt;/span&gt; (&lt;span style=&quot;color: #a71d5d; font-style: italic;&quot;&gt;var&lt;/span&gt; i &lt;span style=&quot;color: #794938;&quot;&gt;in&lt;/span&gt; columns)
                {
                    columns[i].isSortable &lt;span style=&quot;color: #794938;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #811f24; font-weight: 700;&quot;&gt;false&lt;/span&gt;;
                    columns[i].isAutoFilterable &lt;span style=&quot;color: #794938;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #811f24; font-weight: 700;&quot;&gt;false&lt;/span&gt;;
                }
                jsGridContainer.jsgrid.UpdateColumns(&lt;span style=&quot;color: #794938;&quot;&gt;new&lt;/span&gt; &lt;span style=&quot;color: #bf4f24;&quot;&gt;SP.JsGrid&lt;/span&gt;.ColumnInfoCollection(columns));
                jsGridContainer.jsgrid.AttachEvent(SP.JsGrid.EventType.OnEntryRecordPropertyChanged, &lt;span style=&quot;color: #a71d5d; font-style: italic;&quot;&gt;function&lt;/span&gt;(args) {
                    &lt;span style=&quot;color: #794938;&quot;&gt;if&lt;/span&gt; (args.fieldKey &lt;span style=&quot;color: #794938;&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color: #794938;&quot;&gt;=&lt;/span&gt; orderColumnName)
                    {
                        &lt;span style=&quot;color: #a71d5d; font-style: italic;&quot;&gt;var&lt;/span&gt; update &lt;span style=&quot;color: #794938;&quot;&gt;=&lt;/span&gt; SP.JsGrid.CreateUnvalidatedPropertyUpdate(args.recordKey,orderColumnName,currentPageId,&lt;span style=&quot;color: #811f24; font-weight: 700;&quot;&gt;false&lt;/span&gt;);
                        &lt;span style=&quot;color: #693a17;&quot;&gt;setTimeout&lt;/span&gt;(&lt;span style=&quot;color: #a71d5d; font-style: italic;&quot;&gt;function&lt;/span&gt;() {jsGridContainer.jsgrid.UpdateProperties([update], SP.JsGrid.UserAction.UserEdit);}, &lt;span style=&quot;color: #811f24; font-weight: 700;&quot;&gt;100&lt;/span&gt;);
                    }
                });
            });
        });
    &amp;lt;/&lt;span style=&quot;color: #bf4f24;&quot;&gt;script&lt;/span&gt;&amp;gt;
&amp;lt;/&lt;span style=&quot;color: #bf4f24;&quot;&gt;PublishingWebControls:EditModePanel&lt;/span&gt;&amp;gt;
&lt;/pre&gt;
&lt;br /&gt;
&lt;div&gt;
Я не стану здесь пускаться в долгие объяснения о том, как устроен JSGrid - это, пожалуй, материал для целой отдельной серии статей.&lt;br /&gt;
&lt;br /&gt;
Отмечу лишь, что для того, чтобы все заработало, вам необходимо будет добавить в представление списка колонку &quot;Order&quot;. Как можно заметить выше, приведенный код ее скрывает от пользователя, и заполняет значением currentPageId каждый раз, когда добавляется новая строка. Переменную currentPageId я получил, используя следующий фрагмент кода, добавленный перед тегом со скриптом:&lt;/div&gt;
&lt;br /&gt;
&lt;pre style=&quot;background: #f9f9f9; color: #080808;&quot;&gt;&amp;lt;&lt;span style=&quot;color: #bf4f24;&quot;&gt;script&lt;/span&gt; &lt;span style=&quot;color: #bf4f24;&quot;&gt;type&lt;/span&gt;=&lt;span style=&quot;color: #0b6125;&quot;&gt;&quot;text/javascript&quot;&lt;/span&gt;&amp;gt;
    &lt;span style=&quot;color: #a71d5d; font-style: italic;&quot;&gt;var&lt;/span&gt; currentPageId &lt;span style=&quot;color: #794938;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #794938;&quot;&gt;&amp;lt;&lt;/span&gt;SharePointWebControls:NumberField ControlMode&lt;span style=&quot;color: #794938;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #0b6125;&quot;&gt;&quot;Display&quot;&lt;/span&gt; FieldName&lt;span style=&quot;color: #794938;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #0b6125;&quot;&gt;&quot;1d22ea11-1e32-424e-89ab-9fedbadb6ce1&quot;&lt;/span&gt; runat&lt;span style=&quot;color: #794938;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #0b6125;&quot;&gt;&quot;server&quot;&lt;/span&gt;/&lt;span style=&quot;color: #794938;&quot;&gt;&amp;gt;&lt;/span&gt;;
&amp;lt;/&lt;span style=&quot;color: #bf4f24;&quot;&gt;script&lt;/span&gt;&amp;gt;
&lt;/pre&gt;
&lt;br /&gt;
Результат:
&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzqvvb8iCW1ojSFzHLh9vmM4dKfTCr-ivPpCs94zcUqzTqt2xa-GzdxeI1S6is90xtvU5d-nZGzBjAFuDlsoEcclZbMnahMOaqVnqWxsDxCtacSkrjwcuRTW15pmccSspCdFKdg8WFjM4/s1600/page_final.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzqvvb8iCW1ojSFzHLh9vmM4dKfTCr-ivPpCs94zcUqzTqt2xa-GzdxeI1S6is90xtvU5d-nZGzBjAFuDlsoEcclZbMnahMOaqVnqWxsDxCtacSkrjwcuRTW15pmccSspCdFKdg8WFjM4/s1600/page_final.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Полный код фрагмента, который получился у меня для XLV, я выложил на pastebin: &lt;a href=&quot;http://pastebin.com/3TJCcc8f&quot;&gt;http://pastebin.com/3TJCcc8f&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3&gt;
Заключение&lt;/h3&gt;
&lt;div&gt;
SharePoint предлагает огромное количество &quot;строительных блоков&quot; и вариантов их интеграции друг с другом. На основе этих средств в последнее время мне удается решать большинство задач по SharePoint всего за несколько часов.&lt;br /&gt;
&lt;br /&gt;
Однако, необходимо понимать, что даже несмотря все это, множество ограничений и &lt;strike&gt;багов&lt;/strike&gt;подводных камней приводят к тому, что очень сложно рассчитать заранее трудозатраты на создание подобных решений и гарантировать их полную работоспособность. Нередко получается, что 90% решения готово за час, а оставшиеся 10% делаются 2-3 дня. В таких случаях важно не буксовать в одном месте, а придумывать и пробовать разные альтернативные варианты - в шарепойнте их всегда очень много.&lt;br /&gt;
&lt;br /&gt;
В общем, удачи вам в ваших решениях, и не стесняйтесь оставлять комментарии, если у вас есть какие-то вопросы или замечания!&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://omlin.blogspot.com/feeds/4709234134241941312/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://omlin.blogspot.com/2014/03/dependent-lists-sharepoint.html#comment-form' title='Комментарии: 23'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/4709234134241941312'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/4709234134241941312'/><link rel='alternate' type='text/html' href='http://omlin.blogspot.com/2014/03/dependent-lists-sharepoint.html' title='Отображение подчиненных списков в SharePoint'/><author><name>Andrei</name><uri>http://www.blogger.com/profile/13548051158654215855</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhCBWFbE2Ooag1ooQs7Rh6aC_Z4-NtuHSDCNG_kYanZF2fSh21T1tKueE10FReZDQ_rkv0tUQu3mlhuzqYLibT3514JDeOU5gcqarPiP3xtSiIPa_-uIed60Rgn_cUgGZ-gmksQO_3uoto/s72-c/solution_schema.png" height="72" width="72"/><thr:total>23</thr:total></entry><entry><id>tag:blogger.com,1999:blog-70467739252625072.post-4500949850444410471</id><published>2013-08-26T11:29:00.000+04:00</published><updated>2013-08-26T21:10:37.529+04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Client Object Model"/><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint2010"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint2013"/><title type='text'>CamlJs 2.0</title><content type='html'>В предыдущем посте я писал немного о том, &lt;a href=&quot;http://omlin.blogspot.com/2013/08/typescript-unit-tests.html&quot;&gt;как мне удалось улучшить условия разработки CamlJs&lt;/a&gt;: про внутренний переход на TypeScript, введение юнит-тестов и визуального diff&#39;а. Благодаря этим внутренним усовершенствованиям, мне удалось быстро привести проект в порядок, добавить в него существенные улучшения и выпустить релиз 2.0, который выходит сегодня, ура! :)&lt;br /&gt;
&lt;br /&gt;
В этом посте я расскажу, что это за улучшения и как &lt;a href=&quot;http://camljs.codeplex.com/&quot;&gt;CamlJs&lt;/a&gt; может облегчить запросы к спискам в ваших проектах.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Зачем нужен CamlJs&lt;/h3&gt;
&lt;br /&gt;
Итак, проект CamlJs позволяет формировать строку Caml Query на стороне клиента (в JavaScript) для использования совместно с SP.CamlQuery или SPServices. CamlJs привносит следующие основные преимущества перед использованием просто строк с XML:&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;&lt;b&gt;Читаемость.&lt;/b&gt; Захардкоженный XML в коде выглядит жутковато и громоздко, запросы написанные на CamlJs читать намного проще и они гораздо компактнее.
&lt;br/&gt;&lt;br/&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihiXoVQs3Cau7FwdCZoBrZINIt62kbU4q4vK3A5dKRqtkH5YcDByIMzk-PBe7WsABreQqV10qjf8L7TeMlxyNwwgDM2FWzflvPKHjAStkSvn46wiziwjZID5b0CuD3TGvfMkN2_jjRsec/s640/camlbuilder_benefits.png&quot; width=&quot;800&quot; /&gt;&lt;br/&gt;&lt;br/&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Защита от опечаток.&lt;/b&gt; XML - это по сути &quot;magic string&quot;, в котором очень легко сделать опечатку. SharePoint в этом случае возвращает, как водится, совершенно безумные, вводящие в заблуждение сообщения об ошибках. Чтобы понять, что на самом деле ты где-то просто забыл закрывающую кавычку или что-то в этом духе, приходится тратить кучу времени...&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Intellisense.&lt;/b&gt; CamlJs дает intellisense и inline подсказки, благодаря чему даже люди, не в совершенстве знающие CAML Query, могут составлять сложные запросы без ошибок.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Обработка SharePoint-овских &quot;багофич&quot;.&lt;/b&gt; Например, многие ли из вас знают, что при попытке применить условие &amp;lt;Includes&amp;gt; для MultiLookup полей указывающих на поле типа DateTime SharePoint вернет ошибку? :) А CamlJs знает это - и еще кучу тонкостей, которые я собрал за долгие годы работы с CAML Query...&lt;/li&gt;
&lt;/ol&gt;
&lt;br /&gt;
&lt;h3&gt;
Что нового в версии 2.0&lt;/h3&gt;
&lt;br /&gt;
Версия 2.0 существенно улучшена по сравнению с 1.0. При этом, синтаксически версии оставлены максимально совместимыми.&lt;br /&gt;
&lt;div&gt;
&lt;div&gt;
&lt;ol&gt;
&lt;li&gt;&lt;b&gt;Поддержка скобочных выражений и генерации частей запросов.&lt;/b&gt; CamlJs 1.0 не поддерживал возможности создания скобочных выражений. Все операции в запросах генерились строго в порядке справа налево, и более-менее сложную логику с множеством вложенных Or и And реализовать было, к сожалению, невозможно :( Теперь это исправлено за счет введения операторов All и Any.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Значительно улучшен Intellisense.&lt;/b&gt; Теперь набор возможных сравнений для поля зависит от типа этого поля, т.е. например к полям Integer нельзя применить сравнение Contains и т.д.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Изменена обработка Lookup-полей.&lt;/b&gt; Теперь элемент LookupField поддерживает методы Id() и ValueAs&amp;lt;type&amp;gt;(), которые уже в свою очередь возвращают корректный набор операций. Например, если у вас есть Lookup-поле &quot;City&quot;, которое ссылается на текстовое поле &quot;Title&quot; в таблице &quot;Cities&quot;, то чтобы получить все записи у которых город начинается на &quot;М&quot;, надо использовать запрос LookupField(&quot;City&quot;).ValueAsText().BeginsWith(&quot;M&quot;).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Улучшен элемент UserField.&lt;/b&gt; Помимо изменений связанных с изменениями Lookup-полей (а User-поле это как известно частный случай Lookup-а), функционал элемента Membership теперь реализуется несколькими функциями элемента UserField. Кроме того, для удобства, была добавлен метод &quot;EqualToCurrentUser()&quot;, который функционально эквивалентен конструкции &quot;EqualTo(CamlBuilder.CamlValues.UserId)&quot;.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Улучшен элемент DateRangesOverlap.&lt;/b&gt; К сожалению, выяснилось что этот элемент невозможно использовать вместе с SP.CamlQuery, поскольку CSOM игнорирует тэг QueryOptions, а для DateRangesOverlap нужно задавать QueryOptions/CalendarDate и QueryOptions/ExpandRecurrence. Однако, остается возможность использовать DateRangesOverlap хотя бы вместе с SPServices.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Добавлен новый элемент BooleanField&lt;/b&gt; для полей типа Boolean.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Добавлен новый элемент UrlField&lt;/b&gt; для полей типа URL.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DateField и DateTimeField теперь конвертируют дату (Date) к правильному формату.&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
Также, проект теперь написан на TypeScript и покрыт юнит-тестами, благодаря чему можно гарантировать повышенные стабильность и правильность работы.&lt;br /&gt;
&lt;br /&gt;
Наконец, проект теперь доступен через Nuget (добавляет camljs.js в папку Scripts вашего проекта):&lt;br /&gt;
&lt;br /&gt;
&lt;code style=&quot;-o-transform-origin: 360px 34.5px; -webkit-border-bottom-left-radius: 5px; -webkit-border-bottom-right-radius: 5px; -webkit-border-radius: 5px; -webkit-border-top-left-radius: 5px; -webkit-border-top-right-radius: 5px; -webkit-box-shadow: #6E6E6E 2px 2px 3px 0px; -webkit-transform-origin: 360px 34.5px; background: #202020; border-bottom: 4px solid #C0C0C0; border-left: 4px solid #C0C0C0; border-radius: 5px; border-right: 4px solid #C0C0C0; border-top: 4px solid #C0C0C0; box-shadow: #6E6E6E 2px 2px 3px 0px; color: #e2e2e2; display: block; font: normal normal 400 20.4px/30.6px; padding: 7px 5px; width: 600px;&quot;&gt;
PM&amp;gt; Install-Package CamlJs
&lt;/code&gt;
&lt;br /&gt;
Определения для TypeScript также доступны через Nuget:&lt;br /&gt;
&lt;br /&gt;
&lt;code style=&quot;-o-transform-origin: 360px 34.5px; -webkit-border-bottom-left-radius: 5px; -webkit-border-bottom-right-radius: 5px; -webkit-border-radius: 5px; -webkit-border-top-left-radius: 5px; -webkit-border-top-right-radius: 5px; -webkit-box-shadow: #6E6E6E 2px 2px 3px 0px; -webkit-transform-origin: 360px 34.5px; background: #202020; border-bottom: 4px solid #C0C0C0; border-left: 4px solid #C0C0C0; border-radius: 5px; border-right: 4px solid #C0C0C0; border-top: 4px solid #C0C0C0; box-shadow: #6E6E6E 2px 2px 3px 0px; color: #e2e2e2; display: block; font: normal normal 400 20.4px/30.6px; padding: 7px 5px; width: 600px;&quot;&gt;
PM&amp;gt; Install-Package camljs.TypeScript.DefinitelyTyped
&lt;/code&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Миграция с версии 1.0 на 2.0&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;br /&gt;
Логика работы системы осталась в основном прежней, никакие старые элементы не были удалены или переименованы, поэтому как правило, миграция &lt;b&gt;НЕ требуется&lt;/b&gt;. Однако, т.к. синтаксис стал немного более строгим, возможно потребуется что-то подкорректировать. Если у вас возникли проблемы с запросами из версии 1.0, смело пишите в комментарии, решим.&lt;br /&gt;
&lt;br /&gt;
Также, обратите пожалуйста внимание на то, что элементы Membership и LookupIdField теперь помечены как &quot;deprecated&quot; и будут убраны в следующем большом релизе. Рекомендуется переписать запросы с их использованием на эквивалентные конструкции LookupField(&quot;...&quot;).Id() и UserField(&quot;...&quot;).IsInCurrentUserGroups() и т.д.&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h3&gt;
Заключение&lt;/h3&gt;
&lt;div&gt;
&lt;br /&gt;
В SharePoint 2013 роль JavaScript неимоверно возросла. Появилась необходимость создания комплексных JavaScript-решений, работающих полностью на стороне клиента. В этих условиях, приобретают повышенное значение всевозможные инструменты и расширения для клиентских операций, в том числе и разрабатываемый мною opensource-проект CamlJs.&lt;br /&gt;
&lt;br /&gt;
Надеюсь, CamlJs поможет вам улучшить ваши JavaScript-решения и упростить реализацию задач, связанных с генерацией сложных запросов к спискам. Удачи!&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://omlin.blogspot.com/feeds/4500949850444410471/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://omlin.blogspot.com/2013/08/camljs-20.html#comment-form' title='Комментарии: 3'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/4500949850444410471'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/4500949850444410471'/><link rel='alternate' type='text/html' href='http://omlin.blogspot.com/2013/08/camljs-20.html' title='CamlJs 2.0'/><author><name>Andrei</name><uri>http://www.blogger.com/profile/13548051158654215855</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihiXoVQs3Cau7FwdCZoBrZINIt62kbU4q4vK3A5dKRqtkH5YcDByIMzk-PBe7WsABreQqV10qjf8L7TeMlxyNwwgDM2FWzflvPKHjAStkSvn46wiziwjZID5b0CuD3TGvfMkN2_jjRsec/s72-c/camlbuilder_benefits.png" height="72" width="72"/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-70467739252625072.post-5273298465178636897</id><published>2013-08-19T09:30:00.000+04:00</published><updated>2013-08-19T11:11:11.357+04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="EcmaScript"/><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint2010"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint2013"/><title type='text'>Про TypeScript и Unit-test&#39;ы</title><content type='html'>Недавно для своего opensource-проекта &lt;a href=&quot;http://camljs.codeplex.com/&quot;&gt;CamlJs.codeplex.com&lt;/a&gt; (aka SharePoint EcmaScript Caml Builder) потребовалось написать юнит-тесты. При этом раскопал несколько приятных полезностей, которыми собственно и хочу поделиться в этой статье.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
CamlJs&lt;/h3&gt;
&lt;br /&gt;
На всякий случай, для тех кто возможно не в курсе, суть этого проекта - удобное формирование XML Caml-запросов для SP.CamlQuery и/или для SPServices, с интеллисенсом и подсказками. Выглядит это примерно так:&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgmFVgEoKkA1OZcYnr3nMEwjiS9nqEpLIw3j8n2I_qZYSejGEc5dj9nlL7EHsnMtwWz1MRjS8pXia4uyfpUQNfuS-LaBZ-ihrIFfecAFFvweCiylHP9If0Nh9qf3QFcoLpUQOP1d38xboA/s1600/camlbuilder_benefits.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgmFVgEoKkA1OZcYnr3nMEwjiS9nqEpLIw3j8n2I_qZYSejGEc5dj9nlL7EHsnMtwWz1MRjS8pXia4uyfpUQNfuS-LaBZ-ihrIFfecAFFvweCiylHP9If0Nh9qf3QFcoLpUQOP1d38xboA/s1600/camlbuilder_benefits.png&quot; style=&quot;height: 95%; width: 95%;&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Особенность проекта в том, что он действительно не только бережет от опечаток, но практически основной целью при создании CamlJS являлось создание качественного интеллисенса и подсказок, чтобы не требовалось быть экспертом в Caml Query чтобы написать средний запрос.&lt;br /&gt;
&lt;br /&gt;
Проект, даже на самой ранней стадии, представлял довольно внушительную гору JavaScript, довольно тяжеловесную в поддержке. В общем, переход на TypeScript был очень логичным шагом и значительно облегчил поддержку проекта и его дальнейшую разработку. Собственно благодаря переходу на TypeScript какая-то дальнейшая работа и стала возможной - сейчас как раз веду работы по новому синтаксису и готовлюсь релизить... :)&lt;br /&gt;
&lt;br /&gt;
При всём этом, проект практически идеален для юнит-тестов: XML-запросы, которые должен генерировать билдер - это просто строки, которые очень легко проверить. Сначала я проводил тестирование &quot;кустарно&quot; - написал файлик и напулял туда простых сравнений. Конечно же со временем этого стало не хватать и проект дозрел до введения уже нормальных юнит-тестов.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
tsUnit&lt;/h3&gt;
&lt;br /&gt;
Простенький движок для юнит-тестов на TypeScript существует - это &lt;a href=&quot;http://tsunit.codeplex.com/&quot;&gt;tsUnit&lt;/a&gt;. Пользоваться примерно так: наследуемся от класса tsUnit.TestClass, используем методы класса-родителя для assert&#39;ов, и плюс потребуется простенький код инициализации.&lt;br /&gt;
&lt;br /&gt;
Пример использования (с сайта проекта):&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;background-color: white; color: black;&quot;&gt;
&lt;pre&gt;&lt;span style=&quot;color: green;&quot;&gt;/// &amp;lt;reference path=&quot;tsUnit.ts&quot; /&amp;gt;&lt;/span&gt;
&lt;span style=&quot;color: green;&quot;&gt;/// &amp;lt;reference path=&quot;Calculations.ts&quot; /&amp;gt;&lt;/span&gt;

&lt;span style=&quot;color: blue;&quot;&gt;class&lt;/span&gt; SimpleMathTests &lt;span style=&quot;color: blue;&quot;&gt;extends&lt;/span&gt; tsUnit.TestClass {

    &lt;span style=&quot;color: blue;&quot;&gt;private&lt;/span&gt; target = &lt;span style=&quot;color: blue;&quot;&gt;new&lt;/span&gt; Calculations.SimpleMath();

    addTwoNumbersWith1And2Expect3() {
        &lt;span style=&quot;color: blue;&quot;&gt;var&lt;/span&gt; result = &lt;span style=&quot;color: blue;&quot;&gt;this&lt;/span&gt;.target.addTwoNumbers(1, 2);

        &lt;span style=&quot;color: blue;&quot;&gt;this&lt;/span&gt;.areIdentical(3, result);
    }

    addTwoNumbersWith3And2Expect5() {
        &lt;span style=&quot;color: blue;&quot;&gt;var&lt;/span&gt; result = &lt;span style=&quot;color: blue;&quot;&gt;this&lt;/span&gt;.target.addTwoNumbers(3, 2);

        &lt;span style=&quot;color: blue;&quot;&gt;this&lt;/span&gt;.areIdentical(4, result); &lt;span style=&quot;color: green;&quot;&gt;// Deliberate error&lt;/span&gt;
    }
}

&lt;span style=&quot;color: green;&quot;&gt;// new instance of tsUnit&lt;/span&gt;
&lt;span style=&quot;color: blue;&quot;&gt;var&lt;/span&gt; test = &lt;span style=&quot;color: blue;&quot;&gt;new&lt;/span&gt; tsUnit.Test();

&lt;span style=&quot;color: green;&quot;&gt;// add your test class (you can call this multiple times)&lt;/span&gt;
test.addTestClass(&lt;span style=&quot;color: blue;&quot;&gt;new&lt;/span&gt; CalculationsTests.SimpleMathTests());

&lt;span style=&quot;color: green;&quot;&gt;// Use the built in results display&lt;/span&gt;
test.showResults(document.getElementById(&lt;span style=&quot;color: #a31515;&quot;&gt;&#39;results&#39;&lt;/span&gt;), test.run());
&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;h3&gt;
Неудобства&lt;/h3&gt;
&lt;br /&gt;
Однако мне хотелось заточить движок под CamlJs так, чтобы с тестами было работать проще, и в случае проваленного теста было бы проще найти ошибку. Я видел следующие 2 основных неудобства при работе с тестами:&lt;br /&gt;
&lt;br /&gt;
Во-первых, CamlJs генерирует неформатированный XML, и как следствие строка-образец тоже должна быть неформатированной. В итоге в тесты приходилось запихивать километровые строки с XML, что выглядело очень некрасиво и совершенно нечитабельно.&lt;br /&gt;
&lt;br /&gt;
Во-вторых, в случае больших комплексных запросов с кучей вложенных скобочных выражений, когда тест падал, чрезвычайно сложно было найти, в чем же проблема. Например, попробуйте выяснить, что именно здесь не так :)&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgh9xOZhnTQo8JZkFe_uAQnhFLawd8BlQzfeSxbrKP72j7SGePpVXp3LOQ0O4at-1o8WF_q9N_kzCGN9ez3n6XrJgdGp6UhtmZNsKuIwp8d62IKII_V7ZUkAtNO25PFwn8evCKKTzzCEFQ/s1600/testoutcome.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgh9xOZhnTQo8JZkFe_uAQnhFLawd8BlQzfeSxbrKP72j7SGePpVXp3LOQ0O4at-1o8WF_q9N_kzCGN9ez3n6XrJgdGp6UhtmZNsKuIwp8d62IKII_V7ZUkAtNO25PFwn8evCKKTzzCEFQ/s1600/testoutcome.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
Идеальным решением в этом случае была бы, безусловно, подсветка отличий (diff).&lt;br /&gt;
&lt;br /&gt;
Давайте рассмотрим, как я решил эти проблемы.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Сравнение форматированного и неформатированного XML в JavaScript&lt;/h3&gt;
&lt;br /&gt;
После нескольких попыток, я предпочел решить проблему хранения XML-простыней в коде тестов путем перегонки обоих кусков XML в объекты и затем в JSON через JSON.stringify и сравнения уже JSON-строк. Таким образом, я смогу хранить XML-фрагменты в коде тестов в форматированном виде, что улучшит читабельность кода.&lt;br /&gt;
&lt;br /&gt;
Когда-то давно я &lt;a href=&quot;http://omlin.blogspot.com/2011/07/xml-sharepoint-javascript.html&quot;&gt;писал&lt;/a&gt; про то, что в SharePoint есть встроенная функция для превращения XML-строки в dom element. Эта функция прекрасно работает, однако оказалось, что получившийся dom-объект нельзя сериализовать через JSON.stringify (вообще никакие dom-элементы через JSON.stringify не выводятся)! Готового решения этой проблемы я не нашел, но быстро написал простенькую функцию на основе фрагмента из интернетов, которая dom-элемент перегоняет в объект JavaScript. Функция эта выглядит следующим образом:&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;background-color: white; color: black;&quot;&gt;
&lt;pre&gt;        &lt;span style=&quot;color: blue;&quot;&gt;function&lt;/span&gt; elementToObject(el) {
            &lt;span style=&quot;color: blue;&quot;&gt;var&lt;/span&gt; o = {};
            &lt;span style=&quot;color: blue;&quot;&gt;var&lt;/span&gt; i = 0;
            &lt;span style=&quot;color: blue;&quot;&gt;if&lt;/span&gt; (el.attributes) {
                &lt;span style=&quot;color: blue;&quot;&gt;for&lt;/span&gt; (i; i &amp;lt; el.attributes.length; i++) {
                    o[el.attributes[i].name] = el.attributes[i].value;
                }
            }

            &lt;span style=&quot;color: blue;&quot;&gt;var&lt;/span&gt; children = el.childNodes;
            &lt;span style=&quot;color: blue;&quot;&gt;if&lt;/span&gt; (children.length) {
                i = 0;
                &lt;span style=&quot;color: blue;&quot;&gt;for&lt;/span&gt; (i; i &amp;lt; children.length; i++) {
                    &lt;span style=&quot;color: blue;&quot;&gt;if&lt;/span&gt; (children[i].nodeName == &lt;span style=&quot;color: #a31515;&quot;&gt;&#39;#text&#39;&lt;/span&gt;)
                        o[&lt;span style=&quot;color: #a31515;&quot;&gt;&#39;#text&#39;&lt;/span&gt;] = children[i].nodeValue;
                    &lt;span style=&quot;color: blue;&quot;&gt;else&lt;/span&gt;
                        o[children[i].nodeName] = elementToObject(children[i]);
                }
            }
            &lt;span style=&quot;color: blue;&quot;&gt;return&lt;/span&gt; o;
        }
&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
Дальше элементарно:&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;background-color: white; color: black;&quot;&gt;
&lt;pre&gt;&lt;span style=&quot;color: blue;&quot;&gt;var&lt;/span&gt; domElement = CUI.NativeUtility.createXMLDocFromString(&lt;span style=&quot;color: #a31515;&quot;&gt;&quot;&amp;lt;root&amp;gt;&quot;&lt;/span&gt; + xml + &lt;span style=&quot;color: #a31515;&quot;&gt;&quot;&amp;lt;/root&amp;gt;&quot;&lt;/span&gt;);
&lt;span style=&quot;color: blue;&quot;&gt;var&lt;/span&gt; obj = elementToObject(domElement);
&lt;span style=&quot;color: blue;&quot;&gt;return&lt;/span&gt; JSON.stringify(obj.root, undefined, 2);
&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
В результате XML из скриншота выше преобразуется вот в такой кусок более ёмкого и читабельного JSON&#39;а:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt; {
   &quot;Where&quot;:  {
     &quot;And&quot;:  {
       &quot;In&quot;:  {
         &quot;FieldRef&quot;:  {
           &quot;Name&quot;: &quot;Category&quot;  },
         &quot;Values&quot;:  {
           &quot;Value&quot;:  {
             &quot;Type&quot;:  &quot;Integer&quot;,
             &quot;#text&quot;:  &quot;10&quot;
           }
         }
       },
       &quot;Leq&quot;:  {
         &quot;FieldRef&quot;:  {
           &quot;Name&quot;:  &quot;ExpirationDate&quot;
         },
         &quot;Value&quot;:  {
           &quot;Type&quot;:  &quot;Date&quot;,
           &quot;Now&quot;:  {}
         }
       }
     }
   },
   &quot;OrderBy&quot;:  {
     &quot;FieldRef&quot;:  {
       &quot;Name&quot;:  &quot;ExpirationDate&quot;,
       &quot;Ascending&quot;:  &quot;False&quot;
     }
   }
 }
&lt;/pre&gt;
&lt;br /&gt;
Обратите внимание: неважно, что этот JSON не идеальный. Нет задачи сделать идеальный JSON, есть задача сравнить 2 XML&#39;а.&lt;br /&gt;
&lt;br /&gt;
Итоговый код&amp;nbsp;моих юнит-тестов для проекта CamlJs (включая хелпер для реализации преобразования XML-&amp;gt;Json)&amp;nbsp;можно найти &lt;a href=&quot;https://camljs.codeplex.com/SourceControl/latest#CamlBuilder.Test/Layouts/CamlBuilder/Tests.ts&quot;&gt;на Codeplex&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Возвращаясь к неудобствам: даже имея результаты выполнения в форматированном JSON, сравнение запросов в случае проваленного теста по прежнему являлось серьезной проблемой, т.к. запросы большие и приходилось постоянно скроллить туда-сюда, пытаясь найти отличия. Так что давайте теперь рассмотрим, как я сделал diff :)&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Визуальный Diff на JavaScript&lt;/h3&gt;
На самом деле, тут всё банально, есть &lt;a href=&quot;http://ejohn.org/projects/javascript-diff-algorithm/&quot;&gt;готовая библиотека, которая делает diff на js&lt;/a&gt;. Мне пришлось только немного пропатчить tsUnit, чтобы обеспечить интеграцию. В итоге получилась вот такая картинка:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6mAPyE9VBSyKiSA4ZhaccIXNm1ODB9ptp4ztVk9TXW1lygB89kWS3XOPjDy_FZtdpucE7-mZup6U9WAvXZq1GsaPvHoI3ZAz3GepWBdG2l7uuWYqFGG4hmtPhK6Ixj-QvErhhYQihxNo/s1600/camlbuilder_tests_visualdiff.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6mAPyE9VBSyKiSA4ZhaccIXNm1ODB9ptp4ztVk9TXW1lygB89kWS3XOPjDy_FZtdpucE7-mZup6U9WAvXZq1GsaPvHoI3ZAz3GepWBdG2l7uuWYqFGG4hmtPhK6Ixj-QvErhhYQihxNo/s1600/camlbuilder_tests_visualdiff.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Сразу видно, что происходит, удобно, работа ускорилась в разы.&lt;br /&gt;
&lt;br /&gt;
Библиотека не идеальная и ищет отличия в словах (т.е. если у вас текст без пробелов, толку от неё мало). Лично мне хватило, т.к. я использую форматирование JSON и как следствие, везде где надо пробелы стоят. Однако есть более крутые библиотеки, и их довольно много. В частности, есть очень хорошая либа &lt;a href=&quot;http://code.google.com/p/google-diff-match-patch/&quot;&gt;google-diff-match-patch&lt;/a&gt; от Neil Fraser, я на неё поздновато наткнулся, но алгоритм там более подходящий для моих целей, и библиотека сама очень развитая.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Выводы&lt;/h3&gt;
Если подумать серьезно о том, что я делал выше, можно сказать следующее:&lt;br /&gt;
&lt;br /&gt;
Скорость и качество разработки непосредственно зависят от того, насколько хорошо вы подогнали под себя свою рабочую среду. Если вы постоянно будете терять много времени на выполнении какой-то пусть даже несложной второстепенной задачи, внимание начнет рассеиваться, а эффективность - падать. Так что заботьтесь о том, чтобы работать было удобно.&lt;br /&gt;
&lt;br /&gt;
С другой стороны, очень важно здесь не переусердствовать. Нельзя писать систему чтобы писать систему :) Есть простое решение проблемы - отлично, применяем быстро, и продолжаем работать над основным проектом. Быстро не получилось? Значит без этого &quot;удобства&quot; можно обойтись.&lt;br /&gt;
&lt;br /&gt;
Так что, удобной разработки, и до скорых встреч!</content><link rel='replies' type='application/atom+xml' href='http://omlin.blogspot.com/feeds/5273298465178636897/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://omlin.blogspot.com/2013/08/typescript-unit-tests.html#comment-form' title='Комментарии: 4'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/5273298465178636897'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/5273298465178636897'/><link rel='alternate' type='text/html' href='http://omlin.blogspot.com/2013/08/typescript-unit-tests.html' title='Про TypeScript и Unit-test&#39;ы'/><author><name>Andrei</name><uri>http://www.blogger.com/profile/13548051158654215855</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgmFVgEoKkA1OZcYnr3nMEwjiS9nqEpLIw3j8n2I_qZYSejGEc5dj9nlL7EHsnMtwWz1MRjS8pXia4uyfpUQNfuS-LaBZ-ihrIFfecAFFvweCiylHP9If0Nh9qf3QFcoLpUQOP1d38xboA/s72-c/camlbuilder_benefits.png" height="72" width="72"/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-70467739252625072.post-3878415006598219816</id><published>2013-08-16T09:20:00.000+04:00</published><updated>2013-08-16T09:20:00.537+04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint2010"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint2013"/><category scheme="http://www.blogger.com/atom/ns#" term="XSLT"/><title type='text'>XSLT мертв. R.I.P. Да здравствует CSR!</title><content type='html'>Для тех, кто еще может быть не в теме - и я знаю, такие есть: XSLT в SharePoint 2013 был эффективно убит.&lt;br /&gt;
&lt;br /&gt;
Да, конечно, мы всё также можем использовать веб-части с XSLT и почти всегда это будет работать. Но есть нюансы:&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;ol&gt;
&lt;li&gt;Изъят мощнейший инструмент для разработки XSLT - SharePoint Designer. Точнее, изъята та его часть, которая относилась к генерации XSLT. Кое-что можно по-прежнему выжать из местами оставшихся кнопок на Ribbon в Code View, но даже для простейших представлений код веб-частей генерируется нередко нерабочий. Иными словами, это уже неподдерживаемый функционал, которым пользоваться нереально.&lt;/li&gt;
&lt;li&gt;XSLT-преобразования очевидно уже стоят в низком приоритете для команды тестирования SharePoint. Как следствие - уже сейчас, в SP2013, начинают накапливаться баги, связанные с работой XSLT. Пример: в js, который используется для свертывания/развертывания групп при наличии группировки в DataFormWebPart - в SP2013 содержит ошибку. Т.е. группировку в этой веб-части невозможно использовать &quot;OOTB&quot;, придется этот баг исправлять подменяя SharePoint&#39;овскую js-функцию. Я наткнулся на этот баг, когда пытался мигрировать свой &lt;a href=&quot;http://markeev.com/&quot;&gt;английский блог&lt;/a&gt;, который у меня сделан на SharePoint 2010 :(&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;Представлен концептуально новый подход к отображению данных (Client Side Rendering ака CSR), и сейчас ни одна веб-часть в SharePoint по умолчанию более НЕ использует XSLT преобразования. Все списки показываются с помощью CSR, и результаты поиска - тоже.&lt;/li&gt;
&lt;li&gt;CSR действительно лучше, и нет ни единой причины не предпочесть его старому подходу. Это JavaScript templating engine, пусть корявый, но всё-таки JS как язык является гораздо более мощным, более развитым и более современным средством разработки, чем XSLT. Под JavaScript, словно грибы, растут фреймворки, создаются метаязыки (coffee script, TypeScript, Script#, etc.), пишутся библиотеки, расширяются его возможности (html5) и т.д. и т.п. А когда вы слышали последний раз про усовершенствования в XSLT? :)&lt;/li&gt;
&lt;/ol&gt;
XSLT в SharePoint 2013 был эффективно убит. И это факт.&lt;br /&gt;
&lt;br /&gt;
И если в SP2010 еще можно поработать с XSLT (но без излишнего рвения, не забывайте что могут возникнуть проблемы с миграцией), то если вы начинаете новый проект на SP2013, забудьте об XSLT. Начинайте учить CSR.&lt;br /&gt;
&lt;br /&gt;
CSR сыроват и не без своих тараканов. Но он уже лучше XSLT. Многие вещи на CSR делаются в 3 раза быстрее, чем на XSLT, а еще есть вещи на XSLT вообще нельзя было сделать, а на CSR они делаются на раз-два-три.&lt;br /&gt;
&lt;br /&gt;
В проекте &lt;a href=&quot;http://sptypescript.codeplex.com/&quot;&gt;SPTypeScript&lt;/a&gt; мы сделали на момент написания этой статьи уже 6 примеров по использованию CSR:&lt;br /&gt;
&lt;div&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;http://sptypescript.codeplex.com/SourceControl/latest#SPTypeScript/Sample_CSRTabs/CSRTabs.ts&quot;&gt;Разбиение формы на вкладки&lt;/a&gt;&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYw9fvYrJZz66jpHOnjdajpifMBUbYAX7PV3SwJ5snHkjVgoQYvjrzJgD_KWEwkqR161vruTHhwX0UmheGTGNgiY0RxHJZb4Y5C8M-nOR0v-4Db5ovfIrwcWjPP2lsm0B3-pa4Vl_A2yk/s1600/954694_525778860804597_1529498790_n.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYw9fvYrJZz66jpHOnjdajpifMBUbYAX7PV3SwJ5snHkjVgoQYvjrzJgD_KWEwkqR161vruTHhwX0UmheGTGNgiY0RxHJZb4Y5C8M-nOR0v-4Db5ovfIrwcWjPP2lsm0B3-pa4Vl_A2yk/s1600/954694_525778860804597_1529498790_n.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://sptypescript.codeplex.com/SourceControl/latest#SPTypeScript/Sample_FieldLookupBySearch/FieldLookupSearch.ts&quot;&gt;Lookup-поле с автокомплитом, работающим по данным поиска&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://sptypescript.codeplex.com/SourceControl/latest#SPTypeScript/Sample_CustomFieldRendering/CustomFieldRenderingModule/fieldsamples.visafield.ts&quot;&gt;Кастомная валидация полей формы списка&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://sptypescript.codeplex.com/SourceControl/latest#SPTypeScript/Sample_CSRConditionalFormatting/Scripts_ConditionalFormattingList/ConditionalFormatting.ts&quot;&gt;&quot;Color coding&quot; на CSR&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://sptypescript.codeplex.com/SourceControl/latest#SPTypeScript/Sample_CSRComplexityField/CSRField.ts&quot;&gt;Custom Field на CSR&lt;/a&gt; (пример сделан на основе того что есть на MSDN, но внутри код гораздо более правильный и понятный)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://sptypescript.codeplex.com/SourceControl/latest#SPTypeScript/Sample_CSRListView/Scripts_CSRListView/CSRListView.ts&quot;&gt;Custom List View&lt;/a&gt; (очень простой пример из серии &quot;как начать&quot;)&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
Все эти примеры, хотя написаны на TypeScript, доступны параллельно еще и на JS. И к слову, TypeScript генерирует очень даже &lt;b&gt;читабельный&lt;/b&gt; код, честно, я сам был удивлен :) Так что даже если вы не планируете использовать TypeScript, но решили использовать CSR - эти примеры вам могут помочь понять, как оно работает, и избежать многочисленных граблей, которые традиционно присутствуют в ошеломляющих количествах :)&lt;br /&gt;
&lt;br /&gt;
Также, совсем недавно я читал &lt;a href=&quot;http://omlin.blogspot.fi/2013/07/client-side-rendering.html&quot;&gt;доклад про CSR&lt;/a&gt; - очень полезно для старта и освещены некоторые моменты, которых вы врядли где-то еще найдете (да, CSR как это принято в SharePoint&#39;е, документирован процентов на 15% отсилы - а в интернетах еще пока информации маловато).&lt;br /&gt;
&lt;br /&gt;
Подводя итог: на мой взгляд, будущее рендеринга данных в SharePoint - это что-нибудь типа CSR + TypeScript + KnockoutJs. А XSLT, он мертв. И несмотря на человекомесяцы в обнимку с ним и целую пачку статей про него в этом блоге, наверное это и к лучшему :)&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://omlin.blogspot.com/feeds/3878415006598219816/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://omlin.blogspot.com/2013/08/xslt-rip.html#comment-form' title='Комментарии: 5'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/3878415006598219816'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/3878415006598219816'/><link rel='alternate' type='text/html' href='http://omlin.blogspot.com/2013/08/xslt-rip.html' title='XSLT мертв. R.I.P. Да здравствует CSR!'/><author><name>Andrei</name><uri>http://www.blogger.com/profile/13548051158654215855</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYw9fvYrJZz66jpHOnjdajpifMBUbYAX7PV3SwJ5snHkjVgoQYvjrzJgD_KWEwkqR161vruTHhwX0UmheGTGNgiY0RxHJZb4Y5C8M-nOR0v-4Db5ovfIrwcWjPP2lsm0B3-pa4Vl_A2yk/s72-c/954694_525778860804597_1529498790_n.jpg" height="72" width="72"/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-70467739252625072.post-4211303786886102243</id><published>2013-08-05T09:00:00.000+04:00</published><updated>2013-08-05T09:00:03.668+04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint2007"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint2010"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint2013"/><title type='text'>Как я исправил невоспроизводимую ошибку SharePoint с помощью UX-паттерна</title><content type='html'>В прошлый раз я теоретизировал &lt;a href=&quot;http://omlin.blogspot.com/2013/08/usability-ux-sharepoint.html&quot;&gt;о необходимости знаний по UX у SharePoint разработчиков&lt;/a&gt;. Сегодня хочется рассказать об интересном прецеденте использования UX-паттерна для исправления невоспроизводимой ошибки SharePoint.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Дано&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Есть некоторый существующий программный модуль, который позволяет массово создавать сайты. За раз создается обычно от 2х до 18ти сайтов. После создания сайты программно настраиваются. Клиенты используют этот модуль 
пару раз в месяц или даже реже
.&lt;br /&gt;
&lt;br /&gt;
Иногда один или несколько сайтов не создаются по неизвестной причине. Ошибка валится на Webs.Add и она плавающая: то есть, то нет. Более того, по закону подлости она возникает исключительно на production environment. И это еще не всё, когда ко мне попала эта задача, логи с последней ошибкой уже потерлись, поэтому я даже не располагал сообщением об ошибке!...&lt;br /&gt;
&lt;br /&gt;
И тем не менее, я смог решить эту задачу. Прежде чем читать решение, подумайте, что бы вы сделали в такой ситуации?&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Стандартный подход&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Стандартным подходом было бы поочередное исследование кода решения и затем кода Webs.Add через рефлектор, и попытка понять в чем может быть дело (скорее всего неудачная, т.к. Webs.Add довольно быстро уходит в Unmanaged код).&lt;br /&gt;
&lt;br /&gt;
Можно конечно пробовать разные варианты параметров или порядка или какие-нибудь задержки... Но поскольку ошибка не воспроизводится нигде кроме production, а production можно обновлять только раз в 1-2 месяца, да еще и используется этот модуль не интенсивно... В общем методом &quot;тыка&quot; можно было бы растянуть проблему на годы. Собственно, это и происходило - когда я взялся за проблему, она существовала уже больше года.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;UX подход&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Давайте попробуем подойти к проблеме с точки зрения UX. Итак, есть некий интерфейс, пользователь заполняет некоторые поля, выбирает сколько создавать сайтов и т.п. В конце концов, он жмет на кнопку &quot;Создать&quot; - и сайты создаются ...или не создаются, как повезет. Интерфейс в том виде, в котором он попал ко мне, просто глотал все ошибки, всвязи с чем даже непонятно было, какой конкретно сайт не был создан. В результате пользователь шел и проверял, все ли сайты создались, и если нет - то досоздавал их вручную.&lt;br /&gt;
&lt;br /&gt;
В моих любимых &lt;a href=&quot;https://developer.apple.com/library/mac/#documentation/userexperience/conceptual/applehiguidelines/UEGuidelines/UEGuidelines.html&quot;&gt;Apple UX Guidelines&lt;/a&gt; есть следующий пункт:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Trebuchet MS&amp;quot;, sans-serif;&quot;&gt;&lt;b&gt;Display an informative, actionable alert message when something goes wrong.&lt;/b&gt; An alert should clearly convey what happened, why it happened, and the options for proceeding. Describe a workaround if one is available and do whatever you can to prevent the user from losing any data. Avoid using an alert to deliver information that the user can’t act upon.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
В этих четырех предложениях - буквально всё, что вам нужно знать об обработке ошибок! На всякий случай по-русски:&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style=&quot;font-family: &amp;quot;Trebuchet MS&amp;quot;, sans-serif;&quot;&gt;Отображайте информативное, активное сообщение об ошибке (алерт), если что-то пошло не так. &lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;font-family: &amp;quot;Trebuchet MS&amp;quot;, sans-serif;&quot;&gt;Сообщение должно четко описывать что случилось, почему это случилось, и что делать дальше. Опишите воркэраунд, если он существует, и сделайте всё возможное, чтобы предотвратить потерю данных. Не используйте алерты для отображения информации, если пользователь не может ничего с ней сделать.&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;Trebuchet MS&amp;quot;, sans-serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Trebuchet MS&amp;quot;, sans-serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
Что это означает в нашем случае?&lt;br /&gt;
&lt;div&gt;
&lt;ol&gt;
&lt;li&gt;Нельзя &quot;глотать&quot; ошибки создания сайтов.&lt;/li&gt;
&lt;li&gt;При отображении ошибки, необходимо предоставить не только информацию о том, что случилось и почему, но также необходимо предоставить возможность &lt;b&gt;действия&lt;/b&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;b&gt;Решение&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Решение очень простое, но при этом надежное и удобное.&lt;br /&gt;
&lt;br /&gt;
Во-первых, я добавил информацию об ошибке: в случае, если один или несколько сайтов не были созданы, отображается таблица со статусом по каждому из сайтов (Success/Failure).&lt;br /&gt;
&lt;br /&gt;
Во-вторых, рядом с Failure я добавил кнопку Retry. ВСЁ!&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7icqFMM2V1pjbb0QFflqwUTkXsps5IvsgGYtR3EKX4gZ8mfAbDP3JEe4Ue7YF7-oTlKgQVRBZbnTeeYnJU5Ae7qOktJljJmAdsnaiKADDIsfDNuqxnKWSdR6cSnihzqQ14nEIwWYvWrM/s1600/workspaceCreateError.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;271&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7icqFMM2V1pjbb0QFflqwUTkXsps5IvsgGYtR3EKX4gZ8mfAbDP3JEe4Ue7YF7-oTlKgQVRBZbnTeeYnJU5Ae7qOktJljJmAdsnaiKADDIsfDNuqxnKWSdR6cSnihzqQ14nEIwWYvWrM/s640/workspaceCreateError.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Если нажать Retry, модуль попытается пересоздать соответствующий сайт. Если все сайты в итоге удалось создать - то внизу появится ссылка перехода на корневой сайт проекта. Если сайты не пересоздаются - вверху также написано, что делать в этом случае (обратиться к команде поддержки и передать такие-то детали ошибки).&lt;br /&gt;
&lt;br /&gt;
Такие улучшения интерфейса безусловно повлекли за собой некоторое количество работы и немного рефакторинга, т.к. для того, чтобы сделать возможность Retry, пришлось отделить код создания сайтов в обособленный метод, но в любом случае вся работа заняла 2 дня - с большими перерывами на чай и бильярд. Стоит ли говорить, что investigation мог бы занять практически сколько угодно времени и ни к чему не привести?&lt;br /&gt;
&lt;br /&gt;
Отдельно отмечу: это решение полностью закрывает задачу. ПОЛНОСТЬЮ. С точки зрения пользователя, проблемы больше нет. Нажать пару раз кнопку Retry, при том что интерфейс используется пару раз в месяц - да это вообще не вопрос, верно же?&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Выводы&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;
&lt;ol&gt;
&lt;li&gt;Ошибку можно исправить, не исправляя ее&lt;/li&gt;
&lt;li&gt;Я уже писал, что знания по UX меняют сам подход к разработке. И к исправлению ошибок - тоже. Всё, что мы с вами видели выше - это просто подход к решению с другой стороны. Много раз я убеждался, что это реально работает и дает плоды.&lt;/li&gt;
&lt;/ol&gt;
Так что вот. И да пребудет с вами UX! :)&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://omlin.blogspot.com/feeds/4211303786886102243/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://omlin.blogspot.com/2013/08/sharepoint-ux.html#comment-form' title='Комментарии: 21'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/4211303786886102243'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/4211303786886102243'/><link rel='alternate' type='text/html' href='http://omlin.blogspot.com/2013/08/sharepoint-ux.html' title='Как я исправил невоспроизводимую ошибку SharePoint с помощью UX-паттерна'/><author><name>Andrei</name><uri>http://www.blogger.com/profile/13548051158654215855</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7icqFMM2V1pjbb0QFflqwUTkXsps5IvsgGYtR3EKX4gZ8mfAbDP3JEe4Ue7YF7-oTlKgQVRBZbnTeeYnJU5Ae7qOktJljJmAdsnaiKADDIsfDNuqxnKWSdR6cSnihzqQ14nEIwWYvWrM/s72-c/workspaceCreateError.png" height="72" width="72"/><thr:total>21</thr:total></entry><entry><id>tag:blogger.com,1999:blog-70467739252625072.post-7388921190189383127</id><published>2013-08-02T09:00:00.000+04:00</published><updated>2013-08-02T09:00:03.602+04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint2007"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint2010"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint2013"/><title type='text'>Usability и UX в SharePoint</title><content type='html'>SharePoint далеко не идеален с точки зрения Usability, и это ни для кого ни секрет. Однако я заметил, что как ни странно, клиенты в большинстве случаев довольно спокойно относятся к &amp;quot;страшным&amp;quot;, медленным и неудобным интерфейсам в интранете. Более того, когда я предлагаю даже незначительные UX-усовершенствования которые не занимают много времени на реализацию, клиенты склонны отказываться...&lt;br&gt;
&lt;br&gt;
&lt;b&gt;&lt;i&gt;Клиенты нормально относятся к страшным и неудобным интерфейсам&lt;/i&gt;&lt;/b&gt;&lt;br&gt;
&lt;br&gt;
Для публичных сайтов и для экстранетов еще можно что-то предлагать, но на интранетах все очень усердно пытаются сэкономить. Даже здесь, в Европе. Факт.&lt;br&gt;
&lt;br&gt;
&lt;a href=&quot;http://omlin.blogspot.com/2013/08/usability-ux-sharepoint.html#more&quot;&gt;Читать дальше »&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://omlin.blogspot.com/feeds/7388921190189383127/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://omlin.blogspot.com/2013/08/usability-ux-sharepoint.html#comment-form' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/7388921190189383127'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/7388921190189383127'/><link rel='alternate' type='text/html' href='http://omlin.blogspot.com/2013/08/usability-ux-sharepoint.html' title='Usability и UX в SharePoint'/><author><name>Andrei</name><uri>http://www.blogger.com/profile/13548051158654215855</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-70467739252625072.post-1232884425363788216</id><published>2013-07-10T09:11:00.002+04:00</published><updated>2013-07-10T09:11:39.930+04:00</updated><title type='text'>Доклад Client Side Rendering</title><content type='html'>Вчера в костромском офисе Софтлайн прочитал доклад о Client Side Rendering.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;iframe allowfullscreen=&#39;allowfullscreen&#39; webkitallowfullscreen=&#39;webkitallowfullscreen&#39; mozallowfullscreen=&#39;mozallowfullscreen&#39; width=&#39;320&#39; height=&#39;266&#39; src=&#39;https://www.youtube.com/embed/3wPAN4eI-mk?feature=player_embedded&#39; frameborder=&#39;0&#39;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://omlin.blogspot.com/feeds/1232884425363788216/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://omlin.blogspot.com/2013/07/client-side-rendering.html#comment-form' title='Комментарии: 18'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/1232884425363788216'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/1232884425363788216'/><link rel='alternate' type='text/html' href='http://omlin.blogspot.com/2013/07/client-side-rendering.html' title='Доклад Client Side Rendering'/><author><name>Andrei</name><uri>http://www.blogger.com/profile/13548051158654215855</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>18</thr:total></entry><entry><id>tag:blogger.com,1999:blog-70467739252625072.post-4689228353532671420</id><published>2013-06-13T09:00:00.000+04:00</published><updated>2013-07-09T20:30:09.180+04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Client Object Model"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint2013"/><category scheme="http://www.blogger.com/atom/ns#" term="Workflow"/><title type='text'>Рабочие процессы SharePoint 2013: Workflow Services API в примерах</title><content type='html'>В &lt;a href=&quot;http://omlin.blogspot.com/2013/06/sharepoint-2013.html&quot;&gt;предыдущем посте&lt;/a&gt; я очень кратко (но ёмко) прошелся по Workflow в SharePoint 2013. Сегодня хочу продолжить тему и рассказать о новом клиентском API под названием Workflow Services (и показать, как его можно использовать), которое доступно в том числе из SharePoint JavaScript Object Model.&lt;br&gt;
&lt;br&gt;
&lt;a href=&quot;http://omlin.blogspot.com/2013/06/sp.workflowservices.html#more&quot;&gt;Читать дальше »&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://omlin.blogspot.com/feeds/4689228353532671420/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://omlin.blogspot.com/2013/06/sp.workflowservices.html#comment-form' title='Комментарии: 4'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/4689228353532671420'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/4689228353532671420'/><link rel='alternate' type='text/html' href='http://omlin.blogspot.com/2013/06/sp.workflowservices.html' title='Рабочие процессы SharePoint 2013: Workflow Services API в примерах'/><author><name>Andrei</name><uri>http://www.blogger.com/profile/13548051158654215855</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsa0zF8jQAsnnSZE3QIxrtFRkaHSUocRypnDdbjIs5q8yZhTVw9MrUjak8bYnylkJpI9TuHDwO1E_KeabGm5-G1erbvTVdxq-4dnyA9FNVR6dCo-8NilsRRfJ5RHcXaIc58L7dzpLDZQA/s72-c/sptypescript_example_workflowservices.png" height="72" width="72"/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-70467739252625072.post-4268264052009245997</id><published>2013-06-12T09:00:00.000+04:00</published><updated>2013-06-13T10:54:44.727+04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint2013"/><category scheme="http://www.blogger.com/atom/ns#" term="Workflow"/><title type='text'>Рабочие процессы SharePoint 2013</title><content type='html'>В SharePoint 2013 в части рабочих процессов (Workflow) произошли довольно важные перемены - как вы все наверное уже знаете. Постараюсь обобщить в цельную картину, кратко и без маркетингового трепа:&lt;br /&gt;
&lt;div&gt;
&lt;ol&gt;
&lt;li&gt;Самое главное: SharePoint 2013 поддерживает теперь два типа Workflow: старыe (WF3) и новые (&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/ee342461.aspx&quot;&gt;WF4&lt;/a&gt;). Старые крутятся внутри SharePoint как и раньше, а новые хостятся вне SharePoint, в отдельном компоненте под названием Workflow Manager. Чтобы обеспечить работоспособность новой связки, появилось Workflow Service Application, а для непосредственного взаимодействия WF с SharePoint используется механизм Apps.&lt;/li&gt;
&lt;li&gt;В новых Workflow есть циклы, переходы, вызов web-сервисов и других Workflow (что круто), но зато напрочь &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/jj728659.aspx&quot;&gt;отсутствует куча жизненно важных Workflow Actions&lt;/a&gt;, таких как например &quot;Set Approval Status&quot; и некоторых других.&lt;/li&gt;
&lt;li&gt;Reusable Workflow в режиме WF2013 теперь нельзя цеплять к Content Type и нельзя их публиковать на всю коллекцию сайтов (кнопка &quot;Publish Globally&quot; задисейблена). Так что готовьтесь к копипасту :)&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Impersonation Step в новых заменен на &quot;App Step&quot; (подробнее &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/jj822159.aspx&quot;&gt;на MSDN&lt;/a&gt;). Для повышения привилегий используется тот же механизм, что в Apps.&lt;/li&gt;
&lt;li&gt;Есть &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/jj670125.aspx&quot;&gt;interop&lt;/a&gt; - т.е. из новых можно вызывать старые WF. В итоге в реальных проектах вполне ожидаем следующий сценарий: основной РП пишется на WF4, а из него по мере необходимости вызываются WF3-workflow. Напоминает забивание гвоздей микроскопом, но тут уж куда деваться :)&lt;/li&gt;
&lt;li&gt;OOTB-Workflow, такие как Approval, Collect Feedback и т.д. - могут выполняться только в режиме совместимости, т.е. в режиме WF3.&lt;/li&gt;
&lt;li&gt;Custom Workflow Actions теперь декларативные: они представляют собой XOML-файлы, в которых можно использовать &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/jj163790.aspx&quot;&gt;только ограниченный набор Workflow Activities&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Custom Workflow (Code) Activity создавать всё-таки можно, хотя и &lt;strike&gt;через жопу&lt;/strike&gt; &lt;a href=&quot;http://vietsharepoint.blogspot.com/2013/02/sharepoint-2013-deploy-custom-code.html&quot;&gt;сложно&lt;/a&gt; (т.е. в O365 уж точно так сделать не получится). Альтернативно предлагается писать веб-сервисы и вызывать веб-сервисы из Workflow. А что, вариант :)&lt;/li&gt;
&lt;li&gt;Для новых РП теперь есть очень мощное клиентское API (см. мой следующий пост про &lt;a href=&quot;http://omlin.blogspot.fi/2013/06/sp.workflowservices.html&quot;&gt;Workflow Services API&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;В SPD теперь есть новый Workflow Editor (только при наличии Visio на компьютере).&lt;/li&gt;
&lt;li&gt;Обладатели SharePoint Foundation остались без Workflow Manager и как следствие без WF нового типа.&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
Честно сказать, впечатления от нововведений неоднозначные. Для меня самый неприятный момент - это отсутствие некоторых фундаментальных WF activities в РП нового типа. Впрочем, уже есть мысли, как это можно &quot;логически&quot; обойти :)&lt;br /&gt;
&lt;br /&gt;
P.S. Если у кого есть что добавить к моему списку, отпишитесь плиз в комменты!&lt;br /&gt;
&lt;br /&gt;
&lt;em&gt;&lt;span style=&quot;color: red;&quot;&gt;Update 13.06:&lt;/span&gt; добавил уточнение про Impersonation Step и App Step, невозможность публиковать новые РП на всю коллекцию узлов, и ссылку на новый пост про Workflow Services.&lt;/em&gt;</content><link rel='replies' type='application/atom+xml' href='http://omlin.blogspot.com/feeds/4268264052009245997/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://omlin.blogspot.com/2013/06/sharepoint-2013.html#comment-form' title='Комментарии: 8'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/4268264052009245997'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/4268264052009245997'/><link rel='alternate' type='text/html' href='http://omlin.blogspot.com/2013/06/sharepoint-2013.html' title='Рабочие процессы SharePoint 2013'/><author><name>Andrei</name><uri>http://www.blogger.com/profile/13548051158654215855</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-70467739252625072.post-1599956152708760018</id><published>2013-04-29T09:10:00.000+04:00</published><updated>2013-04-29T10:16:14.202+04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint"/><category scheme="http://www.blogger.com/atom/ns#" term="Workflow"/><title type='text'>Custom Workflow Action: Количество рабочих дней между датами</title><content type='html'>Многие недооценивают/недолюбливают SPD Workflows - это рабочие процессы, которые создаются в SharePoint Designer. Обычный аргумент заключается в том, что они недостаточно гибкие и много чего не позволяют, в то время как де Visual Studio Workflows - это C#, и там уж все можно. Ну-ну :)&lt;br /&gt;
&lt;br /&gt;
На самом деле SharePoint Designer Workflows - очень даже&amp;nbsp;гибкие. Во многом - благодаря возможности создания для них программных Custom Actions, причем эти Custom Actions можно создавать даже для Sandbox, и следовательно - использовать в O365. Ниже я покажу, как это сделать, на реальном примере.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Проблема вычисления количества&amp;nbsp;рабочих дней между датами&lt;/h3&gt;
&lt;br /&gt;
Проблема это известная и не новая. С помощью вычисляемого поля (Calculated Field) можно легко вычислить количество календарных дней между датами, и после некоторых ковыряний даже можно исключить субботу и воскресенье - но как быть с праздниками!? Праздники нередко переносятся туда-сюда, т.е.&amp;nbsp;каждый год решение о распределении праздников принимается нашим правительством, так что предугадать/рассчитать это распределение попросту невозможно: сегодня так решили, а завтра начинают январские праздники на май переносить и т.д. :)&lt;br /&gt;
&lt;br /&gt;
В то же время, например для подсчета длины отпуска, или например Due Date для счета или другого документа - очень пригодилось бы уметь вычислять эту разницу!&lt;br /&gt;
&lt;br /&gt;
Чтобы решить эту проблему, хочешь-не хочешь придется откуда-то брать подготовленные уже данные по праздникам: либо они должны быть заведены вручную, либо можно например взять календарь праздников из Outlook и синхронизировать этот список в SharePoint. И чтобы вытащить эти данные и подсчитать количество рабочих дней, придется конечно писать код, без кода здесь не обойтись.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Почему Custom Workflow Action?&lt;/h3&gt;
&lt;br /&gt;
Workflow заточены для построения бизнес-процессов. Именно в бизнес-процессах требуется знать разницу в рабочих днях чаще всего. Например, для рассылки напоминаний исполнителям &quot;за 3 рабочих дня&quot; до истечения срока рассмотрения заявки и т.п.&lt;br /&gt;
&lt;br /&gt;
Как я уже упоминал в своем вводном посте про Workflow, рабочие процессы нужно использовать, когда требуется организовать бизнес-процесс, т.е. взаимодействие системы с людьми, особенно если участников вовлечено в процесс много. Если процесса никакого нет - лучше использовать Event Receiver&#39;ы и Timer Job&#39;ы. Повально использовать WF - идея дурная.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Workflow Action XML&lt;/h3&gt;
&lt;br /&gt;
Самая интересная часть написания Workflow Action - это создание т.н. &quot;Workflow Action Statement&quot;, т.е. определение, как будет внешне выглядеть сконструированный вами шаг процесса.&lt;br /&gt;
&lt;br /&gt;
Это делается полностью через XML. Настройка на удивление очень простая и гибкая. Все начинается с определение атрибута &lt;span style=&quot;color: red;&quot;&gt;Sentence&lt;/span&gt; элемента &lt;span style=&quot;color: #a31515;&quot;&gt;RuleDesigner&lt;/span&gt;. Например, для нашего случая это может выглядеть так:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;code&quot;&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;background: white; color: #a31515;&quot;&gt;RuleDesigner &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;Sentence&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;Count holidays between %1 and %2 (result to %3)&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;br /&gt;
Дальше, как можно догадаться, нужно задать настройки для параметров, определенных через плейсхолдеры &lt;span style=&quot;color: blue;&quot;&gt;%1&lt;/span&gt;, &lt;span style=&quot;color: blue;&quot;&gt;%2&lt;/span&gt; и &lt;span style=&quot;color: blue;&quot;&gt;%3&lt;/span&gt;. Это делается вложенными элементами &lt;span style=&quot;color: #a31515;&quot;&gt;FieldBind&lt;/span&gt;:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;code&quot;&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;background: white; color: #a31515;&quot;&gt;RuleDesigner &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;Sentence&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;Count holidays between %1 and %2 (result to %3)&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;gt;
&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;background: white; color: #a31515;&quot;&gt;FieldBind &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;Field&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;startDate&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;
               &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;Text&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;start date&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot; &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;Id&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;
               &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;DesignerType&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;Date&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot; &lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;/&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style=&quot;background: white; color: #a31515;&quot;&gt;FieldBind &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;Field&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;endDate&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;
               &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;Text&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;end date&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot; &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;Id&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;
               &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;DesignerType&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;Date&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot; &lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;/&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style=&quot;background: white; color: #a31515;&quot;&gt;FieldBind &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;Field&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;Result&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;
               &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;Text&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;HolidaysCount&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot; &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;Id&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;
               &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;DesignerType&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;ParameterNames&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot; &lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;/&amp;gt;
&amp;lt;/&lt;/span&gt;&lt;span style=&quot;background: white; color: #a31515;&quot;&gt;RuleDesigner&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;br /&gt;
Как нетрудно догадаться, атрибут &lt;span style=&quot;color: red;&quot;&gt;Id&lt;/span&gt; задает номер плейсхолдера, атрибут &lt;span style=&quot;color: red;&quot;&gt;Text&lt;/span&gt;&amp;nbsp;задает, какой текст будет отображаться вместо соответствующего плейсхолдера по умолчанию (когда еще не выбрано конкретное значение), а &lt;span style=&quot;color: red;&quot;&gt;Field&lt;/span&gt; - это внутренний идентификатор поля, который потребуется немного позже. Таким образом, в SharePoint Designer заданный таким образом Custom Workflow Action будет выглядеть следующим образом:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigyjzFVqfJthyCvE2l2sysqprxKLmmwmBLpk8I7ey5vbfHeU1SULjlLjIG75gtI0xPBeE5VGsyt47g2bq5TOv5kTmYDLzbY4B7h45e4jVlZUe-L9AyOv-aPnmytxpHQZpfk2goHQsmxvc/s1600/CountHolidays.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigyjzFVqfJthyCvE2l2sysqprxKLmmwmBLpk8I7ey5vbfHeU1SULjlLjIG75gtI0xPBeE5VGsyt47g2bq5TOv5kTmYDLzbY4B7h45e4jVlZUe-L9AyOv-aPnmytxpHQZpfk2goHQsmxvc/s1600/CountHolidays.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
По-моему, здорово! :)&lt;br /&gt;
&lt;br /&gt;
Безусловно, самый интересный атрибут элемента &lt;span style=&quot;color: #a31515;&quot;&gt;FieldBind&lt;/span&gt; - это &lt;span style=&quot;color: red;&quot;&gt;DesignerType&lt;/span&gt;. Например, значение &quot;&lt;span style=&quot;color: blue;&quot;&gt;Date&lt;/span&gt;&quot; для этого атрибута задает вот такой дизайнер для элемента:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEii7K5KXS8Ku06UZBhe7sg6pzTjuLuVXjDNkRPh2zZOhkilXmrlruJhNQ8JaWS1_INXE5JJCsYiZpU7hwVf2Fvf1PupjgFE0ZeWAM5odNZ-Us3c3C89sRAPO603QHKG2dVaO9TLEqvb0mI/s1600/dateDesigner.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEii7K5KXS8Ku06UZBhe7sg6pzTjuLuVXjDNkRPh2zZOhkilXmrlruJhNQ8JaWS1_INXE5JJCsYiZpU7hwVf2Fvf1PupjgFE0ZeWAM5odNZ-Us3c3C89sRAPO603QHKG2dVaO9TLEqvb0mI/s1600/dateDesigner.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Обратите внимание: рядом с полем ввода две кнопки! Одна ([...]) вызывает обозначенный на скриншоте диалог ввода &quot;фиксированного значения&quot; даты/времени. Другая же ([fx]) вызывает стандартный Lookup-диалог, который позволяет вставить значения поля, переменной, параметра и т.п.:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTdwE765C6xXlPiZ3hyP8b79FjuUC9Kh0hSaBB8lbW6sjjWU-0JT3of__9C-oD4Edj3Ph6CI7Ie6Hm7-bdvkTnsBI6I2FdJ6JRnx1OMafYrp6kPOvSP1vxwz93_bXtFSX8pRPFw-YSfA0/s1600/dateDesignerLookup.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTdwE765C6xXlPiZ3hyP8b79FjuUC9Kh0hSaBB8lbW6sjjWU-0JT3of__9C-oD4Edj3Ph6CI7Ie6Hm7-bdvkTnsBI6I2FdJ6JRnx1OMafYrp6kPOvSP1vxwz93_bXtFSX8pRPFw-YSfA0/s1600/dateDesignerLookup.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
Существует, конечно же, множество других типов дизайнеров, которые можно использовать. Есть среди них дизайнеры для разных типов значений - Bool, Integer, Float, Hyperlink и др., есть преднастроенные выпадающие списки: выбор одного из полей текущего списка, выбор одного из списков текущего узла, и т.д., есть выпадающие списки для которых можно задать список значений, а есть даже возможность затянуть список значений из внешнего датасорса (мне правда еще ни разу такое не требовалось). В общем, вариантов масса.&lt;br /&gt;
&lt;br /&gt;
Все комбинации можно посмотреть в файле 14\TEMPLATE\XML\WorkflowActions.xsd. Довольно доходчивое описание, что каждый из этих дизайнеров собой представляет (правда, без скриншотов), можно найти&amp;nbsp;&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/bb897971.aspx&quot;&gt;на MSDN&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Возвращаясь к нашему Custom Action, чтобы оно заработало, надо добавить еще пару штрихов.&lt;br /&gt;
&lt;br /&gt;
На самом деле, возможно даже не все об этом знают,&amp;nbsp;но&amp;nbsp;любой элемент SPD Workflow имеет не только &quot;визуальное&quot; представление в виде конструктора, но также представление в виде PropertyGrid, которое вызывается через пункт контекстного меню &quot;Properties&quot;:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhI0tC-BzcT74RtFP24eTEFhJm-96jgLYVxKZ1fBz3bi6PextJJQE5idKwqmCf7UuJzhTIXKKWDo5zTPN-7ic_W46oqpKLIkwKdKxyOdQ4Y-BNCYGVGoR1U2M42Ub8DTkie_qk0GWQhTI8/s1600/parameters.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhI0tC-BzcT74RtFP24eTEFhJm-96jgLYVxKZ1fBz3bi6PextJJQE5idKwqmCf7UuJzhTIXKKWDo5zTPN-7ic_W46oqpKLIkwKdKxyOdQ4Y-BNCYGVGoR1U2M42Ub8DTkie_qk0GWQhTI8/s1600/parameters.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
В этом представлении может иногда оказаться больше свойств, чем полей в конструкторе шага. Эти свойства также задаются через XML, элементами &lt;span style=&quot;color: #a31515;&quot;&gt;Parameter&lt;/span&gt;, и упомянутый атрибут &lt;span style=&quot;color: red;&quot;&gt;Field &lt;/span&gt;элемента &lt;span style=&quot;color: #a31515;&quot;&gt;FieldBind&lt;/span&gt; как раз должен совпадать с &lt;span style=&quot;color: #a31515;&quot;&gt;Parameter&lt;/span&gt;/&lt;span style=&quot;color: red;&quot;&gt;Name&lt;/span&gt;. Для элементов &lt;span style=&quot;color: #a31515;&quot;&gt;Parameter&lt;/span&gt; задается C#-тип этого параметра, а также направление (&lt;span style=&quot;color: blue;&quot;&gt;In &lt;/span&gt;или &lt;span style=&quot;color: blue;&quot;&gt;Out&lt;/span&gt;) и некоторые другие свойства. Параметры уже непосредственно передаются в C# код, который реализует данный Workflow Action. Вот как выглядит XML, задающий параметры для нашего случая:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;code&quot;&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;background: white; color: #a31515;&quot;&gt;Parameters&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;gt;
  &amp;lt;&lt;/span&gt;&lt;span style=&quot;background: white; color: #a31515;&quot;&gt;Parameter &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;Name&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;__Context&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;
              &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;Type&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;Microsoft.SharePoint.WorkflowActions.WorkflowContext, Microsoft.SharePoint.WorkflowActions&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;
              &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;Direction&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;In&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;
              &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;DesignerType&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;Hide&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;/&amp;gt;
&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;  &amp;lt;&lt;/span&gt;&lt;span style=&quot;background: white; color: #a31515;&quot;&gt;Parameter &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;Name&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;startDate&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;
              &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;Type&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;System.DateTime, mscorlib&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;
              &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;Direction&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;In&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;
              &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;DesignerType&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;Date&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;
              &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;Description&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;Start date of the holidays period&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot; &lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;/&amp;gt;
  &amp;lt;&lt;/span&gt;&lt;span style=&quot;background: white; color: #a31515;&quot;&gt;Parameter &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;Name&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;endDate&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;
              &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;Type&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;System.DateTime, mscorlib&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;
              &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;Direction&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;In&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;
              &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;DesignerType&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;Date&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;
              &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;Description&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;End date of the holidays period&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot; &lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;/&amp;gt;
  &amp;lt;&lt;/span&gt;&lt;span style=&quot;background: white; color: #a31515;&quot;&gt;Parameter &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;Name&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;Result&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;
              &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;Type&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;System.Int32, mscorlib&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;
              &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;Direction&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;Out&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;
              &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;DesignerType&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;ParameterNames&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;
              &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;Description&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;Number of holidays between two dates.&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot; &lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;/&amp;gt;
&amp;lt;/&lt;/span&gt;&lt;span style=&quot;background: white; color: #a31515;&quot;&gt;Parameters&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;br /&gt;
Параметр &lt;span style=&quot;color: blue;&quot;&gt;__Context&lt;/span&gt; - служебный, в процессе исполнения он будет автоматически подменен объектом контекста Workflow.&lt;br /&gt;
&lt;br /&gt;
Обратите внимание, здесь еще раз задается &lt;span style=&quot;color: red;&quot;&gt;DesignerType&lt;/span&gt;. Этот атрибут определяет вид дизайнера в PropertyGrid. Он вполне может отличаться от &lt;span style=&quot;color: red;&quot;&gt;DesignerType&lt;/span&gt; соответствующего элемента &lt;span style=&quot;color: #a31515;&quot;&gt;FieldBind&lt;/span&gt;.&lt;br /&gt;
&lt;br /&gt;
Результирующий PropertyGrid с параметрами заданными приведенным выше XML будет выглядеть следующим образом:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUGegE1IdDUa0IOoGwwJC74FDOdEFACB164Uom7pVy2QgSPaU4MXrr-dy8U71dxiEZAYqPd25y7Ktno4mEJR4bniKOa1CD6TE8LKCltINNgrjKTmuNAJmI-vs8gBRyss0SyXQn0UasRF8/s1600/parametersDialog.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUGegE1IdDUa0IOoGwwJC74FDOdEFACB164Uom7pVy2QgSPaU4MXrr-dy8U71dxiEZAYqPd25y7Ktno4mEJR4bniKOa1CD6TE8LKCltINNgrjKTmuNAJmI-vs8gBRyss0SyXQn0UasRF8/s1600/parametersDialog.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
Сразу отмечу, что порядок элементов&amp;nbsp;&lt;span style=&quot;color: #a31515;&quot;&gt;Parameter&lt;/span&gt;&amp;nbsp;важен. Именно в этом порядке параметры будут передаваться в наш метод-обработчик.&lt;br /&gt;
&lt;br /&gt;
Кроме параметров, еще необходимо задать общие настройки для создаваемого Workflow Action. За это отвечает элемент Action - который будет задавать название нашего Workflow Action, его тип, категорию и т.п. Вот как всё это будет выглядеть в итоге:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;code&quot;&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;  &amp;lt;&lt;/span&gt;&lt;span style=&quot;background: white; color: #a31515;&quot;&gt;WorkflowActions&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style=&quot;background: white; color: #a31515;&quot;&gt;Action &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;Name&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;Count Holidays&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;
            &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;SandboxedFunction&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;
            &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;Assembly&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;$SharePoint.Project.AssemblyFullName$&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;
            &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;ClassName&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;MyProject.CustomActions&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;
            &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;FunctionName&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;CountHolidays&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;
            &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;UsesCurrentItem&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;
            &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;AppliesTo&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;all&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;
            &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;Category&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;Utility Actions&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;gt;
      &amp;lt;&lt;/span&gt;&lt;span style=&quot;background: white; color: #a31515;&quot;&gt;RuleDesigner &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;Sentence&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;Count holidays between %1 and %2 (result to %3)&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;gt;
        ...&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;
      &amp;lt;/&lt;/span&gt;&lt;span style=&quot;background: white; color: #a31515;&quot;&gt;RuleDesigner&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;gt;
      &amp;lt;&lt;/span&gt;&lt;span style=&quot;background: white; color: #a31515;&quot;&gt;Parameters&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;gt;
        ...&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;
      &amp;lt;/&lt;/span&gt;&lt;span style=&quot;background: white; color: #a31515;&quot;&gt;Parameters&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;gt;
    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;background: white; color: #a31515;&quot;&gt;Action&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;gt;
  &amp;lt;/&lt;/span&gt;&lt;span style=&quot;background: white; color: #a31515;&quot;&gt;WorkflowActions&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;br /&gt;
В случае затруднений с XML, примеры определения имеющихся в SharePoint Workflow Actions в XML-виде можно найти в папке 14\TEMPLATE\1033\Workflow, в файлах *.actions.&lt;br /&gt;
&lt;br /&gt;
Да, последнее про XML: этот XML деплоится через модуль, т.е. этот XML-код должен быть помещен в &lt;b&gt;Elements.xml&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Метод-обработчик&lt;/h3&gt;
&lt;br /&gt;
Наконец, XML написан, и теперь можно переходить наконец-то на C#. Как не трудно догадаться, метод-обработчик задается в XML атрибутами &lt;span style=&quot;color: red;&quot;&gt;Assembly&lt;/span&gt;, &lt;span style=&quot;color: red;&quot;&gt;ClassName&lt;/span&gt; и &lt;span style=&quot;color: red;&quot;&gt;FunctionName&lt;/span&gt; элемента &lt;span style=&quot;color: #a31515;&quot;&gt;Action&lt;/span&gt;.&lt;br /&gt;
&lt;br /&gt;
Метод должен возвращать Hashtable, и принимать все параметры обозначенные в XML, строго в том порядке, в котором идут элементы &lt;span style=&quot;color: #a31515;&quot;&gt;Parameter&lt;/span&gt;. Типы, ясное дело, тоже должны соответствовать заявленным. А вот имя параметра можно сделать другим (но лучше тоже чтобы они совпадали, просто чтобы не запутаться потом).&lt;br /&gt;
&lt;br /&gt;
Таким образом, в моем случае сигнатура метода должна выглядеть следующим образом:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;code&quot;&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;public &lt;/span&gt;&lt;span style=&quot;background: white; color: #2b91af;&quot;&gt;Hashtable &lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;CountHolidays(&lt;/span&gt;&lt;span style=&quot;background: white; color: #2b91af;&quot;&gt;SPUserCodeWorkflowContext &lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;context,&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background: white; color: #2b91af;&quot;&gt;DateTime &lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;startDate, &lt;/span&gt;&lt;span style=&quot;background: white; color: #2b91af;&quot;&gt;DateTime &lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;endDate)
&lt;/span&gt;&lt;/pre&gt;
&lt;br /&gt;
Возвращать значения нужно в Hashtable, ключ значения&amp;nbsp;должен соответствовать значению атрибута Parameter/Name в XML. Т.е. в нашем случае будем возвращать значение в hashtable[&quot;Result&quot;].&lt;br /&gt;
&lt;br /&gt;
Зная это, осталось только написать собственно код для подсчета количества выходных согласно заданному вами алгоритму, используя объект контекста и переданные параметры. &lt;br /&gt;
&lt;br /&gt;
Код элементарный и состоит в простейшем случае из одного запроса к списку. Например,&amp;nbsp;он может выглядеть следующим образом:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;code&quot;&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;public &lt;/span&gt;&lt;span style=&quot;background: white; color: #2b91af;&quot;&gt;Hashtable &lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;CountHolidays(&lt;/span&gt;&lt;span style=&quot;background: white; color: #2b91af;&quot;&gt;SPUserCodeWorkflowContext &lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;context,&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background: white; color: #2b91af;&quot;&gt;DateTime &lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;startDate, &lt;/span&gt;&lt;span style=&quot;background: white; color: #2b91af;&quot;&gt;DateTime &lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;endDate)
{

    &lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;using &lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;background: white; color: #2b91af;&quot;&gt;SPSite &lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;site = &lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;new &lt;/span&gt;&lt;span style=&quot;background: white; color: #2b91af;&quot;&gt;SPSite&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;(context.CurrentWebUrl))
    {
        &lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;using &lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;background: white; color: #2b91af;&quot;&gt;SPWeb &lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;web = site.OpenWeb())
        {
            &lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;try
            &lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;{
                &lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;var &lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;list = web.Lists[context.ListId];
                &lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;var &lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;item = list.GetItemById(context.ItemId);
                        
                &lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;var &lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;holidaysList = &lt;span style=&quot;color: green;&quot;&gt;// здесь получайте список с праздниками&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;
                &lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;var &lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;query = &lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;new &lt;/span&gt;&lt;span style=&quot;background: white; color: #2b91af;&quot;&gt;SPQuery&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;()
                {
                    ViewFields = &lt;/span&gt;&lt;span style=&quot;background: white; color: #a31515;&quot;&gt;@&quot;&amp;lt;FieldRef Name=&quot;&quot;ID&quot;&quot; /&amp;gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;,
                    ViewFieldsOnly = &lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;,
                    Query = &lt;/span&gt;&lt;span style=&quot;background: white; color: #2b91af;&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;.Format(&lt;/span&gt;&lt;span style=&quot;background: white; color: #a31515;&quot;&gt;@&quot;&amp;lt;Where&amp;gt;
                        &amp;lt;And&amp;gt;
                            &amp;lt;Geq&amp;gt;
                                &amp;lt;FieldRef Name=&quot;&quot;{0}&quot;&quot; /&amp;gt;
                                &amp;lt;Value IncludeTimeValue=&quot;&quot;FALSE&quot;&quot; Type=&quot;&quot;DateTime&quot;&quot;&amp;gt;{1}&amp;lt;/Value&amp;gt;
                            &amp;lt;/Geq&amp;gt;
                            &amp;lt;Lt&amp;gt;
                                &amp;lt;FieldRef Name=&quot;&quot;{0}&quot;&quot; /&amp;gt;
                                &amp;lt;Value IncludeTimeValue=&quot;&quot;FALSE&quot;&quot; Type=&quot;&quot;DateTime&quot;&quot;&amp;gt;{2}&amp;lt;/Value&amp;gt;
                            &amp;lt;/Lt&amp;gt;
                        &amp;lt;/And&amp;gt;
                        &amp;lt;/Where&amp;gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;, 
&lt;span style=&quot;background: white; color: #a31515;&quot;&gt;                        &quot;HolidayDateFieldInternalName&quot;&lt;/span&gt;, 
                        &lt;/span&gt;&lt;span style=&quot;background: white; color: #2b91af;&quot;&gt;SPUtility&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;.CreateISO8601DateTimeFromSystemDateTime(startDate.Date), 
                        &lt;/span&gt;&lt;span style=&quot;background: white; color: #2b91af;&quot;&gt;SPUtility&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;.CreateISO8601DateTimeFromSystemDateTime(endDate.Date.AddDays(1)))
                };
&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;var &lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;items = holidaysList.GetItems(query);

                &lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;return new &lt;/span&gt;&lt;span style=&quot;background: white; color: #2b91af;&quot;&gt;Hashtable&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;() { { &lt;/span&gt;&lt;span style=&quot;background: white; color: #a31515;&quot;&gt;&quot;Result&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;, items.Count } };
            }
            &lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;catch &lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;background: white; color: #2b91af;&quot;&gt;Exception &lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;ex)
            {
                &lt;/span&gt;&lt;span style=&quot;background: white; color: #2b91af;&quot;&gt;SPWorkflow&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;.CreateHistoryEvent(web, context.WorkflowInstanceId, 0, web.CurrentUser, &lt;/span&gt;&lt;span style=&quot;background: white; color: #2b91af;&quot;&gt;TimeSpan&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;.Zero, &lt;/span&gt;&lt;span style=&quot;background: white; color: #a31515;&quot;&gt;&quot;Error&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;, ex.Message + &lt;/span&gt;&lt;span style=&quot;background: white; color: #a31515;&quot;&gt;&quot; Stack trace: &quot; &lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;+ ex.StackTrace, &lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;.Empty);
                &lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;return new &lt;/span&gt;&lt;span style=&quot;background: white; color: #2b91af;&quot;&gt;Hashtable&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;() { { &lt;/span&gt;&lt;span style=&quot;background: white; color: #a31515;&quot;&gt;&quot;Result&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;, 0 } };
            }
        }
    }

}

&lt;/span&gt;&lt;/pre&gt;
В список выходных в этом случае&amp;nbsp;должны быть занесены&amp;nbsp;все выходные, включая субботы и воскресенья. Другой вариант - использовать список, в который занесены правила распределения выходных на текущий год, а субботы и воскресенья вычислять в коде.&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;Замечание&lt;/strong&gt;: приведенные выше код и XML относятся к созданию &lt;strong&gt;Sandboxed&lt;/strong&gt; Workflow Custom Action.&amp;nbsp;Обычные серверные Custom Workflow&amp;nbsp;Actions имеют свои преимущества - к примеру, они позволяют запускать код с повышенными привилегиями, что в Sandbox&#39;е сделать не получится. Такие Workflow Actions работают немного по-другому и определение метода будет другим (хотя XML примерно&amp;nbsp;такой же). Как создавать серверные Workflow Actions, описано например &lt;a href=&quot;http://msmvps.com/blogs/sundar_narasiman/archive/2010/12/26/develop-custom-workflow-activity-for-sharepoint-2010-workflow.aspx&quot;&gt;здесь&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Где еще взять Workflow Custom Actions&lt;/h3&gt;
&lt;br /&gt;
На codeplex можно найти десятки Custom Actions, уже созданных для вас. Вы можете использовать их как пример, дорабатывать, изменять и т.п. - ведь это Opensource!&amp;nbsp;Например, &lt;a href=&quot;http://spdactivities.codeplex.com/&quot;&gt;spdactivities.codeplex.com&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Кроме&amp;nbsp;того, есть компании, которые продают пакеты Custom Actions, и там попадаются очень даже интересные элементы. Например, &lt;a href=&quot;http://www.harepoint.com/Products/HarePointWorkflowExtensions/Default.aspx&quot;&gt;HarePoint Workflow Extensions&lt;/a&gt;&amp;nbsp;- сам не использовал, но на взгляд выглядит интересно.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Заключение&lt;/h3&gt;
&lt;br /&gt;
SPD Workflow -&amp;nbsp;на самом деле очень даже гибкая штука, благодаря возможности создания собственных Workflow Actions. В SharePoint 2013, как известно, Visual Studio Workflows уже работают вообще только&amp;nbsp;в режиме совместимости...</content><link rel='replies' type='application/atom+xml' href='http://omlin.blogspot.com/feeds/1599956152708760018/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://omlin.blogspot.com/2013/04/working-days-workflow-action.html#comment-form' title='Комментарии: 12'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/1599956152708760018'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/1599956152708760018'/><link rel='alternate' type='text/html' href='http://omlin.blogspot.com/2013/04/working-days-workflow-action.html' title='Custom Workflow Action: Количество рабочих дней между датами'/><author><name>Andrei</name><uri>http://www.blogger.com/profile/13548051158654215855</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigyjzFVqfJthyCvE2l2sysqprxKLmmwmBLpk8I7ey5vbfHeU1SULjlLjIG75gtI0xPBeE5VGsyt47g2bq5TOv5kTmYDLzbY4B7h45e4jVlZUe-L9AyOv-aPnmytxpHQZpfk2goHQsmxvc/s72-c/CountHolidays.png" height="72" width="72"/><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-70467739252625072.post-1697774125756608605</id><published>2013-04-26T09:00:00.000+04:00</published><updated>2013-04-26T09:32:55.224+04:00</updated><title type='text'>Про эффективность и продуктивность</title><content type='html'>Делать быстро&amp;nbsp;и делать именно то, что надо - это идеал, который на самом деле никому не нужен. Да-да, я не ошибся! Реальность - грустная штука и иногда нелогичная, но от нее никуда не убежать :(&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Моя история&lt;/h3&gt;
&lt;br /&gt;
Примерно два с половиной года назад я пришел к следующему выводу: у меня&amp;nbsp;достаточно знаний и опыта, я хорошо схватываю, я прекрасно решаю задачи, я даже в некотором роде люблю SharePoint :),&amp;nbsp;но.... Но очень рассеян, часто отвлекаюсь. Не хватает концентрации, не хватает самодисциплины. В результате проваливаю сроки,&amp;nbsp;целыми днями страдаю фигней и т.п.&amp;nbsp;Не хватает, вроде как,&amp;nbsp;совсем немногого, чтобы быть &quot;очень классным&quot; :) К такому заключению я пришел, повторюсь,&amp;nbsp;около&amp;nbsp;2.5&amp;nbsp;лет назад, и решил, что надо это менять.&lt;br /&gt;
&lt;br /&gt;
Итак,&amp;nbsp;я стал работать над тем, чтобы стать лучше. Выяснилось, чтобы этого добиться, нужно &quot;прокачать&quot; два основных&amp;nbsp;скилла:&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Продуктивность - это умение работать максимально быстро, но без потери качества.&lt;/li&gt;
&lt;li&gt;Результативность - это умение работать на результат, т.е. делать правильные вещи, чтобы достигнуть цели.&lt;/li&gt;
&lt;/ol&gt;
Почувствуйте тонкую разницу! Т.е. нужно не только уметь работать быстро, нужно еще уметь делать правильные вещи. Если вы быстро сделаете какую-то задачу, но поймете ее неправильно - какова цена вашим трудам? Если вы классно сделаете какой-нибудь функционал, но потом окажется, что клиенту он не очень то был и нужен - как вы будете себя чувствовать потом? :)&lt;br /&gt;
&lt;br /&gt;
Итак, что я делал, чтобы этого добиться:&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Установил &lt;a href=&quot;https://www.rescuetime.com/&quot;&gt;RescueTime&lt;/a&gt;&amp;nbsp;(в минимальном, бесплатном варианте). Очень классная утилита, которая позволяет отследить, сколько ты работаешь в том или ином приложении. Приложения распределены по категориям, и каждая категория&amp;nbsp;оценивается от -2 до +2&amp;nbsp;(это все настраивается). Фишка состоит в том, что через месяц-два тебе&amp;nbsp;надоедает постоянно следить за своими отчетами, НО умный RescueTime присылает еженедельные отчеты, и сразу видно, если &quot;расслабился&quot; и надо &quot;подтянуть&quot; концентрацию.&lt;/li&gt;
&lt;li&gt;Читал статьи, смотрел&amp;nbsp;доклады по этой теме - особенно&amp;nbsp;&lt;a href=&quot;http://www.hanselman.com/blog/OredevKeynoteInformationOverloadAndManagingTheFlowEffectivenessAndEfficiency.aspx&quot;&gt;классный&amp;nbsp;доклад от Хансельмана&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Стал планировать свои дела - кстати&amp;nbsp;не только рабочие, но и персональные (такие в частности, как отъезд в Финляндию и все необходимое для этого).&lt;/li&gt;
&lt;li&gt;Изучал Usability и&amp;nbsp;UX, чтобы понимать, что действительно удобно для пользователей, а что нет. Как следствие, я&amp;nbsp;начал задавать более правильные вопросы при анализе задач, и соответственно, стал работать с большей результативностью и с большей пользой для всех.&lt;/li&gt;
&lt;/ol&gt;
На самом деле, много всего читал, много всяких подходов&amp;nbsp;пробовал. Что-то давало результат, что-то нет. В конечном итоге, мне удалось значительно продвинуться в обоих умениях, и как минимум &lt;strong&gt;субъективно&lt;/strong&gt;, я чувствую что стал работать гораздо быстрее (очень сильно быстрее, примерно в 2-3 раза)&amp;nbsp;и уделять больше внимания действительно важным вещам.&lt;br /&gt;
&lt;br /&gt;
Однако, несмотря на все эти успехи, я стал замечать, что иногда быть продуктивным - вредно!...&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Почему быть слишком продуктивным - вредно?&lt;/h3&gt;
&lt;br /&gt;
Вся штука в том, что&amp;nbsp;люди не захотят вам платить, если вы делаете свою работу слишком легко и быстро. Это человеческая психология: если мы не видим стараний и усилий, не видим что человек &quot;пашет&quot; - мы не хотим ему платить и мы&amp;nbsp;меньше ценим его труд.&lt;br /&gt;
&lt;br /&gt;
Простой пример: вот представьте, что есть очень классный спец, который восстанавливает данные с&amp;nbsp;умерших жестких дисков. Вы приходите к нему и просите восстановить данные. Он говорит: 10 тысяч рублей. Вы спрашиваете: а когда будет готово? Он говорит: это сложная процедура, займет 2 недели. Вы говорите ок, отлично (про себя думая: ну нифига себе, это ему две недели работать, за 10 тыс. рублей, ну да, тут никуда не денешься, придется платить).&lt;br /&gt;
&lt;br /&gt;
А теперь представьте другую ситуацию: вы приходите к этому же человеку, и цена такая же - 10 тысяч рублей, но на вопрос &quot;когда будет готово?&quot; он отвечает - приходите через полчаса, будет готово.&lt;br /&gt;
&lt;br /&gt;
И здесь вы начинаете чувствовать себя некомфортно. &quot;Нифига себе молодец,&quot; - думаете вы, - &quot;10 тысяч за полчаса. Это кто ж такие деньги зарабатывает!&quot;.&lt;br /&gt;
&lt;br /&gt;
Как видите, хотя во втором случае специалист, получается, как бы более крутой и более опытный и более знающий, и он может восстановить ваши данные за каких-то полчаса, но в этом случае вам&amp;nbsp;не очень хочется ему&amp;nbsp;платить, и велика вероятность, что вы совсем забросите идею восстанавливать данные&amp;nbsp;или не поверите ему и обратитесь к другому специалисту и т.д.&lt;br /&gt;
&lt;br /&gt;
Точно также происходит и в рабочей обстановке. Если&amp;nbsp;начальнику кажется, что работник слишком легко решает задачи - поверьте, подсознательно он будет думать что скорее всего это просто задачи такие простые.&lt;br /&gt;
&lt;br /&gt;
А если начальник еще вдобавок&amp;nbsp;видит, что вы не работаете, а половину времени на компьютере проводите за своими делами - он обязательно подумает что вы лодырь, причем практически вне зависимости от того сколько задач вы закрыли по сравнению со своими коллегами...&lt;br /&gt;
&lt;br /&gt;
Это человеческая психология, это неизбежно, и практически ни один начальник не способен избежать хотя бы подсознательной недооценки вашей пользы и ценности (тем более, что традиционно продуктивность и эффективность программистов очень сложно оценить). Как следствие - зарплаты очень мало зависят от действительных способностей, знаний и умений&amp;nbsp;программистов.&lt;br /&gt;
&lt;br /&gt;
(Если кому-то интересно узнать, почему так происходит - рекомендую курс Dan Arley про иррациональное поведение &lt;a href=&quot;https://class.coursera.org/behavioralecon-001/lecture/index&quot;&gt;на Coursera&lt;/a&gt;)&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Почему работать целый день без остановки - нельзя в принципе?&lt;/h3&gt;
&lt;br /&gt;
По многим причинам:&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Во-первых, мозгам нужен отдых и время на смену &quot;контекста&quot; между задачами.&lt;/li&gt;
&lt;li&gt;Во-вторых, для решения многих задач вообще говоря нужно время, чтобы они &quot;поварились&quot; у вас в голове. Это из серии &quot;утро вечера мудренее&quot;.&lt;/li&gt;
&lt;li&gt;В-третьих, если вам все-таки удастся работать постоянно и без передышки,&amp;nbsp;у вас просто будут скорее всего&amp;nbsp;очень быстро заканчиваться задачи и возникнут т.н. &quot;периоды ожидания&quot;, которые вас будут расслаблять, а ваше начальство будет беситься, потому что им придется платить за то что вы ничего не&amp;nbsp;делаете и&amp;nbsp;ждете, а кто это любит?...&lt;/li&gt;
&lt;/ol&gt;
На практике это означает, что нельзя сидеть за компьютером 8 часов в день и писать код. Это неправильно и неэффективно. Т.е. рано или поздно вы себя обнаружите гуляющим по офису и &quot;ничего не делающим&quot; с точки зрения начальства. Это неизбежно.&lt;br /&gt;
&lt;br /&gt;
Если соединить эти рассуждения с тем, о чем я рассказывал в предыдущем параграфе, получаем, что эффективным и продуктивным людям НИКТО не хочет платить деньги. Это факт :)&lt;br /&gt;
&lt;br /&gt;
Кстати отсюда же напрямую исходит, что невозможно сократить часы своей работы официальными методами. Например, я хороший специалист, я хочу работать 4 часа в день вместо 8, и больше тратить на семью.&amp;nbsp;Я уверен, что я буду делать не меньше по объему за 4 часа, чем мой сосед &quot;Вася&quot; за 8 - и хочу получать за 4 часа такую же зарплату, как он за восемь. НЕ ПОЛУЧИТСЯ! Точнее, делать столько же получится, а получать за 4 часа такую же зарплату - нет. Причем, на вдвое большую зарплату за 8 часов договориться еще реально, но сокращение рабочего дня -&amp;nbsp;нет. Психология, блин.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Как решить эту проблему?&lt;/h3&gt;
&lt;br /&gt;
Очевидный способ - идти в фриланс или создавать свой бизнес. Но эти варианты сопряжены с большими и ненужными рисками, а также с очень большим объемом работы, связанной с&amp;nbsp;поиском клиентов&amp;nbsp;и всяких переговоров с ними, и не каждый на&amp;nbsp;все это&amp;nbsp;согласится (не я - точно).&lt;br /&gt;
&lt;br /&gt;
Но мне кажется, можно кое-что придумать и работая &quot;на дядьку&quot;:&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Надо поменьше&amp;nbsp;показываться начальству/клиентам на глаза, особенно во время работы.&lt;/li&gt;
&lt;li&gt;Надо&amp;nbsp;добиваться положительного фидбэка&amp;nbsp;от клиентов/рецензоров. Выполнять работу хорошо, в сроки, и всегда демонстрировать результат.&lt;/li&gt;
&lt;li&gt;Во время демонстраций, не помешает рассказать о тех трудностях, которые пришлось преодолеть в процессе выполнения этой задачи. Также не помешает упомянуть о том, какие знания и опыт&amp;nbsp;вам помогли в решении этой задачи.&lt;/li&gt;
&lt;li&gt;Желательно&amp;nbsp;выбирать такую работу, в которой не придется заносить часы и не придется отчитываться по каждому часу.&lt;/li&gt;
&lt;li&gt;Свободное время проводить там, где тебя никто не видит, и особо об этом не упоминать.&lt;/li&gt;
&lt;/ol&gt;
Если вкратце, работать нужно так, чтобы никто не видел процесса, а все видели только результат.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Заключение&lt;/h3&gt;
&lt;br /&gt;
Как видите, иногда&amp;nbsp;даже стремиться к лучшему - не всегда хорошо. В реальной жизни, необходимо учитывать человеческую психологию и особенности мира, в котором мы живем. Без этого все старания могут просто стать бессмысленными.&lt;br /&gt;
&lt;br /&gt;
P.S. Не стесняйтесь свои мысли/опыт по этому поводу скидывать в комменты. Обсудим :)</content><link rel='replies' type='application/atom+xml' href='http://omlin.blogspot.com/feeds/1697774125756608605/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://omlin.blogspot.com/2013/04/effectiveness.html#comment-form' title='Комментарии: 11'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/1697774125756608605'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/1697774125756608605'/><link rel='alternate' type='text/html' href='http://omlin.blogspot.com/2013/04/effectiveness.html' title='Про эффективность и продуктивность'/><author><name>Andrei</name><uri>http://www.blogger.com/profile/13548051158654215855</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-70467739252625072.post-9052833680290420299</id><published>2013-04-23T09:00:00.000+04:00</published><updated>2013-04-25T19:43:39.870+04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint"/><category scheme="http://www.blogger.com/atom/ns#" term="SPList"/><title type='text'>Загадочный список Survey</title><content type='html'>Список типа &quot;Опрос&quot; в SharePoint - очень интересный и особенный. Прежде всего, уникальность его заключается в том, что&amp;nbsp;он позволяет вставлять разделители страниц (Page separator), т.е. по сути&amp;nbsp;разбивать форму создания элемента списка на страницы!&lt;br /&gt;
&lt;br /&gt;
Стоит ли говорить, что в реальном мире многостраничные формы и визарды - это очень частая и востребованная опция, повсеместно используемая. К примеру, вы обязательно столкнетесь с необходимостью заполнения многостраничной формы, если будете оформлять загранпаспорт через интернет, или же через интернет покупать билеты на поезд на сайте РЖД, и т.д.
&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXrzeGbKuGMm_O1xCCvVozBIs6xqhrQ3DBt0gHFm3zmk70TOmp5kZnlnGmMd6U031IEaS4aMPIUt202orcpoGrcAunm8CaPfXgmyvN84_-F8dZuTAPaSpEXrA7xMVWbAjko_0D9mFIsaE/s1600/survey_pageSeparator.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXrzeGbKuGMm_O1xCCvVozBIs6xqhrQ3DBt0gHFm3zmk70TOmp5kZnlnGmMd6U031IEaS4aMPIUt202orcpoGrcAunm8CaPfXgmyvN84_-F8dZuTAPaSpEXrA7xMVWbAjko_0D9mFIsaE/s1600/survey_pageSeparator.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Page Separator - это особый тип поля (&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;SPFieldType.PageSeparator&lt;/span&gt;), доступный только для списков типа Survey. По сути это обычная колонка списка, не содержащая никаких данных. Если при выводе полей на форму встречается колонка этого типа, это считается окончанием страницы и следующие поля не выводятся. Также для реализации этого механизма используется параметр командной строки &quot;FirstField&quot;, который определяет, начиная с какого поля выводить форму:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2c5Dhx800YGDOPGKSRHd4rRwdxvJ-ACfbLJgXqGkeY_mmUxJr-PbojOraK9MdNNqv9pvbYOw9CZ7YpvhE01GeM-5Qs7CcYXhsNxxLdQK1HXLgmixHes9D3kXbE5DLtnXv5T0iSFRnt-8/s1600/FirstField.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2c5Dhx800YGDOPGKSRHd4rRwdxvJ-ACfbLJgXqGkeY_mmUxJr-PbojOraK9MdNNqv9pvbYOw9CZ7YpvhE01GeM-5Qs7CcYXhsNxxLdQK1HXLgmixHes9D3kXbE5DLtnXv5T0iSFRnt-8/s1600/FirstField.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
Более того, переходы на разные страницы можно даже сделать условными с помощью фишки, которая называется &quot;Branching logic&quot;:&lt;/div&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizqaqaDTL6MAldGumATU_JLL-fBaSFTFW2Angi5d0Gmp4ef-JgTQeiqXM-dCRFR1KuqTuuFq89jxEHmzhLCc2GLo2pXL3YbotaftJkzBulCT3XifQ4aqQ9GLMsTPIgBMz4dm1pEoH0j-o/s1600/branchingLogic.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizqaqaDTL6MAldGumATU_JLL-fBaSFTFW2Angi5d0Gmp4ef-JgTQeiqXM-dCRFR1KuqTuuFq89jxEHmzhLCc2GLo2pXL3YbotaftJkzBulCT3XifQ4aqQ9GLMsTPIgBMz4dm1pEoH0j-o/s1600/branchingLogic.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
Т.е. в зависимости от выбора пользователя, можно пропустить следующую страницу опроса, и т.д.&lt;br /&gt;
&lt;br /&gt;
Конечно, список типа &quot;Survey&quot; ориентирован прежде всего на создание опросов. Однако, в некоторых ситуациях его вполне можно использовать и для других бизнес нужд. Живой пример: регистрации на встречи Russian SharePoint User Group на сайте rusug.net всегда были реализованы именно с помощью обычного списка &quot;Survey&quot; (хоть и без разбития на страницы).&lt;br /&gt;
&lt;br /&gt;
Однако, если вы хотите сделать свой список и свою форму на основе Survey, необходимо учитывать следующие основные ограничения этого списка:&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Ответить на опрос можно &lt;b&gt;только один раз&lt;/b&gt;. Это автоматически означает, что один пользователь может заполнить форму лишь единожды, т.е. создать только 1 элемент списка. Для регистрации на событие это вполне нормально, а вот оформление заказов таким образом уже не сделаешь...&lt;br/&gt;
&lt;span style=&quot;color:red;&quot;&gt;Update&lt;/span&gt;: Спасибо Алексею за комментарий! Оказывается, при создании списка есть дополнительная опция &quot;Allow multiple responses&quot;, которая решает эту проблему.
&lt;/li&gt;
&lt;li&gt;Бэкэнд заточен под создание вопросов и ответов, и везде используется соответствующая терминология. Если вы планируете давать клиенту возможность изменять этот список (добавлять в него поля и т.п.), надо готовиться, что придется пускаться в пространные объяснения, что это там за вопросы и ответы такие :)&lt;/li&gt;
&lt;li&gt;Веб-интерфейс настроек списка сильно урезан. Например, через настройки списка в браузере нельзя создавать представления (хотя через SharePoint Designer или программно представления создаются без проблем).&lt;/li&gt;
&lt;li&gt;Survey - это, пожалуй, единственный тип списка, у которого до сих пор остался старый тип тулбара, из 2007го SharePoint&#39;а. Интеграция с риббоном отсутствует.&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
Проверки на тип списка, как водится, захардкожены по всему SharePoint&#39;у :) Поэтому обойти эти ограничения непросто, если вообще возможно.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
В основном из-за первого ограничения, довольно сложно использовать Survey-списки для каких-то своих нужд в неизменном виде. Я постарался разобраться во внутреннем устройстве этого типа списка, и выяснить,&amp;nbsp;можно ли обойти его ограничения и использовать сходный подход для создания многостраничной формы.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3&gt;
Как устроен Survey List&lt;/h3&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Оказывается, реализация многостраничности в опросах довольно простая. Она основывается на переопределенном RenderingTemplate. Вы можете найти этот шаблон в файле CONTROLTEMPLATES/DefaultTemplates.ascx, называется SurveyForm:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre class=&quot;code&quot;&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;SharePoint&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;RenderingTemplate &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&quot;SurveyForm&quot; &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;runat&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&quot;server&quot;&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;Template&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;gt;
        &amp;lt;&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;wssuc&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;ToolBar &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;CssClass&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&quot;ms-formtoolbar&quot; &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&quot;toolBarTbltop&quot; &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;RightButtonSeparator&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&quot;&amp;amp;amp;#160;&quot; &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;runat&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&quot;server&quot;&amp;gt;
            &amp;lt;&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;Template_RightButtons&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;gt;
&lt;strong&gt;                &amp;lt;&lt;/strong&gt;&lt;/span&gt;&lt;strong&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;SharePoint&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;NextPageButton &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;runat&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&quot;server&quot;/&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;SharePoint&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;SaveButton &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;Text&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&quot;&lt;/span&gt;&lt;span style=&quot;background: yellow; color: black;&quot;&gt;&amp;lt;%&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;$Resources:wss,tb_survey_save&lt;/span&gt;&lt;span style=&quot;background: yellow; color: black;&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&quot; &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;accesskey&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&quot;&lt;/span&gt;&lt;span style=&quot;background: yellow; color: black;&quot;&gt;&amp;lt;%&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;$Resources:wss,tb_survey_save_AK&lt;/span&gt;&lt;span style=&quot;background: yellow; color: black;&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&quot; &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;runat&lt;/span&gt;&lt;/strong&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&lt;strong&gt;=&quot;server&quot;/&amp;gt;&lt;/strong&gt;
                &amp;lt;&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;SharePoint&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;MultiPageGoBackButton &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;runat&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&quot;server&quot;/&amp;gt;
             &amp;lt;/&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;Template_RightButtons&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;gt;
        &amp;lt;/&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;wssuc&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;ToolBar&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;gt;
        &amp;lt;&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;SharePoint&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;FormToolBar &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;runat&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&quot;server&quot;/&amp;gt;
        &amp;lt;&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;SharePoint&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;ItemValidationFailedMessage &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;runat&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&quot;server&quot;/&amp;gt;
        &amp;lt;&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;table &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&quot;ms-formtable&quot; &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;style&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;margin-top&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;8px&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&quot; &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;border&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&quot;0&quot; &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;cellpadding&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&quot;0&quot; &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;cellspacing&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&quot;0&quot; &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;width&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&quot;100%&quot;&amp;gt;
        &lt;b&gt;&amp;lt;&lt;/b&gt;&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;SharePoint&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;SurveyFieldIterator &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;runat&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&lt;b&gt;=&quot;server&quot;/&amp;gt;&lt;/b&gt;
        &amp;lt;/&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;table&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;gt;
        &amp;lt;&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;table &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;cellpadding&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&quot;0&quot; &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;cellspacing&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&quot;0&quot; &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;width&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&quot;100%&quot;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;tr&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;td &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&quot;ms-formline&quot;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;img &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;src&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&quot;/_layouts/15/images/blank.gif?rev=23&quot; &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;width&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&#39;1&#39; &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;height&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&#39;1&#39; &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;alt&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&quot;&quot; /&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;td&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;tr&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;table&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;gt;
        &amp;lt;&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;table &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;cellpadding&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&quot;0&quot; &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;cellspacing&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&quot;0&quot; &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;width&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&quot;100%&quot; &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;style&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;padding-top&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;7px&quot;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;tr&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;td &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;width&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&quot;100%&quot;&amp;gt;
        &amp;lt;&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;SharePoint&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;ItemHiddenVersion &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;runat&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&quot;server&quot;/&amp;gt;
        &amp;lt;&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;wssuc&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;ToolBar &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;CssClass&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&quot;ms-formtoolbar&quot; &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&quot;toolBarTbl&quot; &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;RightButtonSeparator&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&quot;&amp;amp;amp;#160;&quot; &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;runat&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&quot;server&quot;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;Template_Buttons&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;gt;
                        &amp;lt;&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;SharePoint&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;InitContentType &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;runat&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&quot;server&quot;/&amp;gt;
                        &amp;lt;&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;SharePoint&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;CreatedModifiedInfo &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;runat&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&quot;server&quot;/&amp;gt;
                &amp;lt;/&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;Template_Buttons&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;Template_RightButtons&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;gt;
                    &lt;b&gt;&amp;lt;&lt;/b&gt;&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;SharePoint&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;NextPageButton &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;runat&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&lt;b&gt;=&quot;server&quot;/&amp;gt;&lt;/b&gt;
                    &lt;b&gt;&amp;lt;&lt;/b&gt;&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;SharePoint&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;SaveButton &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;Text&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&quot;&lt;/span&gt;&lt;span style=&quot;background: yellow; color: black;&quot;&gt;&amp;lt;%&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;$Resources:wss,tb_survey_save&lt;/span&gt;&lt;span style=&quot;background: yellow; color: black;&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&quot; &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;accesskey&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&quot;&lt;/span&gt;&lt;span style=&quot;background: yellow; color: black;&quot;&gt;&amp;lt;%&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;$Resources:wss,tb_survey_save_AK&lt;/span&gt;&lt;span style=&quot;background: yellow; color: black;&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&quot; &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;runat&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&lt;b&gt;=&quot;server&quot;/&amp;gt;&lt;/b&gt;
                    &lt;strong&gt;&amp;lt;&lt;/strong&gt;&lt;/span&gt;&lt;strong&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;SharePoint&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;MultiPageGoBackButton &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;runat&lt;/span&gt;&lt;/strong&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&lt;strong&gt;=&quot;server&quot;/&amp;gt;&lt;/strong&gt;
                &amp;lt;/&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;Template_RightButtons&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;gt;
        &amp;lt;/&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;wssuc&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;ToolBar&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;gt;
        &amp;lt;/&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;td&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;tr&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;table&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;gt;
    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;Template&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;gt;
&amp;lt;/&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;SharePoint&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;RenderingTemplate&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;gt;
&lt;/span&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Для многостраничной логики, здесь задействованы контролы, обозначенные жирным. Наиболее интересным на первый взгляд здесь представляется контрол&amp;nbsp;&lt;strong&gt;SurveyFieldIterator&lt;/strong&gt;. Он реализует логику отображения полей на форме. Если подсмотреть на этот класс через рефлектор или его аналог, вы увидите, что логика отображения на удивление простая и даже в некотором роде элегантная (если элегантный говнокод существует - то это как раз он! :) ).&lt;br /&gt;
&lt;br /&gt;
Хорошие новости:&amp;nbsp;&lt;strong&gt;SurveyFieldIterator&lt;/strong&gt; будет работать для любого списка - т.е. довольно легко его задействовать в каком-нибудь другом, кастомном списке.&amp;nbsp;Плохие новости:&amp;nbsp;в контролы &lt;b&gt;NextPageButton &lt;/b&gt;и &lt;b&gt;SaveButton&lt;/b&gt;&amp;nbsp;захардкожены проверки на шаблон списка (SPListTemplateType.Survey), и использовать их в кастомном списке не выйдет :(&lt;br /&gt;
&lt;br /&gt;
Заменить эти контролы очень непросто, потому что они используют некоторые&amp;nbsp;методы, помеченные как internal (т.е. только через Reflection, чего я стараюсь избегать).&amp;nbsp;Обойтись без них тоже никак - ведь именно кнопка &quot;NextPageButton&quot; обеспечивает промежуточное сохранение элемента списка и реализует кучу другой интересной логики. В общем, после нескольких часов ковыряния в рефлекторе, я так и не смог найти нормального способа сделать многостраничный список в SharePoint таким же способом, как сделан список Survey, т.е. через ListFieldIterator... :(&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Помимо невозможности замены NextPageButton, есть кстати&amp;nbsp;и другие ограничения.&amp;nbsp;К примеру,&amp;nbsp;поле PageSeparator через веб-интерфейс доступно только для списков типа Survey. Впрочем, это поле очень легко добавить программно, или&amp;nbsp;например вот таким простейшим PowerShell-скриптом:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;$w = get-spweb http://localhost&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;$l = $w.Lists[&quot;My List&quot;]&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;$l.Fields.Add(&quot;PageSeparator&quot;, [Microsoft.SharePoint.SPFieldType]::PageSeparator, $false, $false, $null)&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
После добавления этого&amp;nbsp;поля, можно перейти в настройки списка и изменить порядок колонок, так чтобы PageSeparator был расположен в нужном вам месте формы. Как правило, число шагов визарда изменяется крайне редко, поэтому давать возможность пользователям добавлять PageSeparator через интерфейс скорее всего не потребуется.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;
Branching Logic иногда тоже было бы полезно использовать, но и&amp;nbsp;эта фишка в UI доступна только для списков типа &quot;Опрос&quot;.&amp;nbsp;Так что тут&amp;nbsp;снова придется либо действовать PowerShell-ом, либо писать отдельный UI - если требуется, чтобы пользователи сами могли настраивать логику отображения формы (что, кстати, требуется крайне редко).&lt;/div&gt;
&lt;br /&gt;
Также, следует отметить, что стандартные кнопки Save и Cancel работать не должны. Впрочем, убрать их с&amp;nbsp;Ribbon&amp;nbsp;довольно легко&amp;nbsp;следующим Custom Action:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;code&quot;&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;CustomAction &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;Id&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&quot;RemoveRibbonButton&quot; &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;Location&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&quot;CommandUI.Ribbon&quot;&amp;gt;
  &amp;lt;&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;CommandUIExtension&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;CommandUIDefinitions&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;gt;
     &amp;lt;&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;CommandUIDefinition &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;Location&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&quot;Ribbon.ListForm.Edit.Commit&quot; /&amp;gt;
    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;CommandUIDefinitions&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;gt;
  &amp;lt;/&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;CommandUIExtension&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;gt;
&amp;lt;/&lt;/span&gt;&lt;span style=&quot;background: white; color: maroon;&quot;&gt;CustomAction&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;br /&gt;
На этом пункте, я посчитал свое исследование законченным, и надеюсь результаты этого исследования вам было интересно читать, пусть мне и не удалось реализовать изначальную мою идею :)&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Заключение&lt;/h3&gt;
&lt;br /&gt;
В SharePoint много вещей, которые мало кто использует и о которых мало кто знает. На удивление, даже программисты с 3-4 летним стажем разработки под SharePoint часто не знают про некоторые базовые функции платформы...&amp;nbsp;Нередко эти вещи можно использовать очень эффективно, сокращая трудозатраты на реализацию того или иного функционала в десятки раз.&lt;br /&gt;
&lt;br /&gt;
К сожалению, далеко не все фишки SharePoint так хороши, как они кажутся на первый взгляд. И многие возможности SharePoint использовать даже, я бы сказал, опасно - можно запросто не вписаться в сроки.&lt;br /&gt;
&lt;br /&gt;
Поэтому, когда хочется использовать какую-то возможность SharePoint, обязательно сначала&amp;nbsp;создайте проект-пример, и чем больше он будет приближенным к тому что вам в итоге нужно - тем лучше. Не бойтесь потратить на исследования даже&amp;nbsp;1-2 дня, потому что вы потратите как минимум в два раза больше, если начнете писать&amp;nbsp;этот код сразу же в основной проект.&lt;br /&gt;
&lt;br /&gt;
Что же касается многостраничных форм - реализовывать их в SharePoint сейчас на удивление тяжело - на мой взгляд это в некотором роде прокол со стороны MS, ведь бизнес-кейс это очень частый. Есть у них&amp;nbsp;конечно полуживой&amp;nbsp;InfoPath и малополезный &lt;a href=&quot;http://blog.mastykarz.nl/multipage-forms-sharepoint-scenario-framework/&quot;&gt;Scenario Framework&lt;/a&gt;, но InfoPath - действительно &lt;a href=&quot;http://omlin.blogspot.fi/2013/03/sharepoint-list-forms-2013.html&quot;&gt;полуживой&lt;/a&gt; и полон собственных ограничений и багов, а Scenario Framework - мало что дает по сравнению с обычным ASP.Net-визардом, созданным&amp;nbsp;&quot;вручную&quot;. В настоящий момент наиболее перспективным подходом к&amp;nbsp;задаче многостраничных форм&amp;nbsp;мне лично&amp;nbsp;видится&amp;nbsp;использование Client Side Rendering (CSR) из SharePoint 2013 - но это пока что подход не проверенный. Если будет шанс реализовать многостраничную форму на CSR, я этим обязательно с вами поделюсь, а&amp;nbsp;на сегодня&amp;nbsp;у меня все. Удачи!&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://omlin.blogspot.com/feeds/9052833680290420299/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://omlin.blogspot.com/2013/04/survey.html#comment-form' title='Комментарии: 6'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/9052833680290420299'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/9052833680290420299'/><link rel='alternate' type='text/html' href='http://omlin.blogspot.com/2013/04/survey.html' title='Загадочный список Survey'/><author><name>Andrei</name><uri>http://www.blogger.com/profile/13548051158654215855</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXrzeGbKuGMm_O1xCCvVozBIs6xqhrQ3DBt0gHFm3zmk70TOmp5kZnlnGmMd6U031IEaS4aMPIUt202orcpoGrcAunm8CaPfXgmyvN84_-F8dZuTAPaSpEXrA7xMVWbAjko_0D9mFIsaE/s72-c/survey_pageSeparator.png" height="72" width="72"/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-70467739252625072.post-208863958862836888</id><published>2013-04-22T09:06:00.000+04:00</published><updated>2013-04-22T11:40:32.957+04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint"/><category scheme="http://www.blogger.com/atom/ns#" term="SPList"/><title type='text'>Атрибуты ViewFields</title><content type='html'>С первого взгляда, ViewFields - это попросту список полей, которые отображаются в том или ином представлении списка. В C# API этот список полей представлен классом &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.spviewfieldcollection.aspx&quot;&gt;SPViewFieldCollection&lt;/a&gt;, который является по сути коллекцией&amp;nbsp;строк, представляющих собой InternalName полей, отображаемых представлением.&lt;br /&gt;
&lt;br /&gt;
Немногие знают, что каждое поле внутри ViewFields (элементы FieldRef) еще&amp;nbsp;может иметь атрибуты, которые определяют, как именно это поле включается в представление списка. Большая часть этих атрибутов присутствует у исходных SPField (однако не все атрибуты SPField переопределяемы!), и установка их в FieldRef позволяет просто переопределить (override) настройки поля в рамках конкретного представления.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Меню элемента&lt;/h3&gt;
&lt;br /&gt;
Пожалуй,&amp;nbsp;одни из самых известных и используемых атрибутов элементов ViewFields - это &lt;strong&gt;LinkToItem&lt;/strong&gt; и &lt;strong&gt;ListItemMenu&lt;/strong&gt;. Они позволяют &quot;подцепить&quot; соответственно ссылку на Display&amp;nbsp;форму&amp;nbsp;элемента и&amp;nbsp;меню элемента&amp;nbsp;на произвольное поле списка - без всяких там&amp;nbsp;XSLT преобразований. Нередко эти атрибуты используются, например, в библиотеках документов, где вместо имени файла предпочтительнее отображать заголовок документа (Title)&amp;nbsp;- и соответственно, меню элемента должно быть перенесено на заголовок.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;code&quot;&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;background: white; color: #a31515;&quot;&gt;FieldRef &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;Name&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;MyField&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot; &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;LinkToItem&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;TRUE&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot; &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;ListItemMenu&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;TRUE&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot; &lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;br /&gt;
В SharePoint 2013, к слову, добавился похожий атрибут &quot;&lt;strong&gt;CalloutMenu&lt;/strong&gt;&quot;, который позволяет отобразить более современное меню&amp;nbsp;элемента&amp;nbsp;вида &quot;Callout&quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Фильтрация и сортировка&lt;/h3&gt;
&lt;br /&gt;
Установка атрибутов&amp;nbsp;&lt;b&gt;Filterable&lt;/b&gt; и &lt;b&gt;Sortable&lt;/b&gt;&amp;nbsp;в FALSE поможет запрещать фильтрацию и сортировку выбранных полей в пределах вашего представления. Дополнительно, можно указать сообщение, которое будет отображаться, когда фильтрация недоступна (атрибут &lt;b&gt;FilterDisableMessage&lt;/b&gt;).&lt;br /&gt;
&lt;br /&gt;
Когда это требуется?&lt;br /&gt;
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Например, вы выносите фильтр по некоторому полю в отдельную панель наверху представления, и улучшаете этот фильтр, делаете его более &quot;user friendly&quot;. Скажем, вместо фильтрации по конкретной дате, вы предлагаете пользователю выбрать месяц/год или даже лучше - выбрать конкретный диапазон дат. В этом случае фильтр в заголовке колонки становится ненужным, и почему бы его не запретить.&lt;/li&gt;
&lt;li&gt;В некоторых полях фильтрация просто выглядит глупо (яркий пример - поле &quot;Title&quot;).&lt;/li&gt;
&lt;li&gt;Когда вы используете в запросе представления (тэг &lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;lt;Query&amp;gt;&lt;/span&gt;) параметры (значения из ParameterBindings), фильтры SharePoint ломаются, т.е. не выдают вариантов для фильтрации, как будто в колонке совсем нет данных. В этом случае я предпочитаю явно запрещать фильтрацию и определять сообщение об ошибке для всех полей, что-нибудь типа &quot;В этом представлении фильтрация невозможна&quot;...&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3&gt;
Explicit&lt;/h3&gt;
&lt;br /&gt;
Исключительно полезный атрибут&amp;nbsp;- &lt;strong&gt;Explicit&lt;/strong&gt;. Значение его трудно переоценить, особенно если вы работаете с какими-то коробочными решениями или с большими проектами, где много пользователей с разными уровнями привилегий. Но даже и на маленьких проектах, этот атрибут часто важен!&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;Explicit&lt;/strong&gt; делает две вещи:&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Скрывает поле из представления. Т.е. данные для поля будут запрашиваться и поступать в XSLT преобразование, но отображаться соответствующие поля не будут, пока вы их сами не отобразите.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Не дает пользователю удалить поле из представления!!&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwlluJBA3y6lxV23dAEL3j9K692R4lY2ggmGXmyypkvvUdL0oK_XnGpuqgCHJBtomRFydbMW1NYloDBjLrOWwy9qNLH3fQMQRJoZuC772vEIzPzymFAMG7O4-Qp-RuIMpc5Fjf5p_PIro/s1600/explicit.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;206&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwlluJBA3y6lxV23dAEL3j9K692R4lY2ggmGXmyypkvvUdL0oK_XnGpuqgCHJBtomRFydbMW1NYloDBjLrOWwy9qNLH3fQMQRJoZuC772vEIzPzymFAMG7O4-Qp-RuIMpc5Fjf5p_PIro/s640/explicit.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
Те люди, которые используют свойство &lt;b&gt;Sealed &lt;/b&gt;у SPField, меня поймут! :)&lt;br /&gt;
&lt;br /&gt;
Для остальных поясню: кастомизированное представление - вещь&amp;nbsp;довольно хрупкая. Удалили критически важное поле из представления - представление разъехалось или начало глючить. А клиенты, они такие&amp;nbsp;- любят удалять &quot;ненужное&quot; :) Нередко бывает, что ошибки замечают не сразу. Проходит несколько дней, в конце концов&amp;nbsp;обнаруживают ошибку, но никто уже не помнит что он там когда-то давно что-то &quot;чистил&quot;. В итоге, клиент с черной тучкой над головой звонит в вашу техподдержку....&lt;br /&gt;
&lt;br /&gt;
SharePoint итак далек от идеала, и дополнительный негатив для клиента создавать на пустом месте&amp;nbsp;безусловно не стоит, даже если вам кажется что он не оправдан. Ошибку можно обрабатывать в коде, но это неправильный подход, и он всегда&amp;nbsp;более дорогой. Идеальный вариант - просто запрещать удалять поля из представления. А &lt;b&gt;Explicit &lt;/b&gt;- это единственный предусмотренный и правильный&amp;nbsp;способ это делать.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
SharePoint 2013&lt;/h3&gt;
&lt;br /&gt;
В SharePoint 2013, помимо уже упоминавшегося выше &lt;b&gt;CalloutMenu&lt;/b&gt;, к ViewFields добавилось немало новых интересных атрибутов. В частности, это атрибуты для управления отображением полей типа &quot;Пользователь&quot;: &lt;b&gt;WithPicture&lt;/b&gt;, &lt;b&gt;PictureSize&lt;/b&gt;, &lt;b&gt;PictureOnly&lt;/b&gt;, и некоторые другие.&lt;br /&gt;
&lt;br /&gt;
Например, добавление &lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;WithPicture=&quot;TRUE&quot;&lt;/span&gt; к полю &quot;Created By&quot; (InternalName=&quot;Author&quot;)&amp;nbsp;выдает вот такой результат:&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2CIf5OoZ2puDL7tJoPkbu7BD11f5AtYXJvRy4nAYmJNH61Cn9SUcfPXXjwRgDfswLehv6oT1Pjmm_ZJwrjTEIJ3mpfR9nwEUHVfNttDg_h6IOb4QMwelYfOnBNzPDINKUG_LDDapAx-8/s1600/withpicture.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2CIf5OoZ2puDL7tJoPkbu7BD11f5AtYXJvRy4nAYmJNH61Cn9SUcfPXXjwRgDfswLehv6oT1Pjmm_ZJwrjTEIJ3mpfR9nwEUHVfNttDg_h6IOb4QMwelYfOnBNzPDINKUG_LDDapAx-8/s1600/withpicture.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
А вот такой FieldRef:

&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;code&quot;&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;background: white; color: #a31515;&quot;&gt;FieldRef &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;Name&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;Author&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot; &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;PictureSize&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;Size_36px&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot; &lt;/span&gt;&lt;span style=&quot;background: white; color: red;&quot;&gt;PictureOnly&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;TRUE&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;&quot; &lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;br /&gt;
Будет отображен следующим образом:&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiY3I5mnlVSSzh8zGJ1F4nSkNU1LI6uBUnQCBUOKh5GzPfCtdHh8TbV7cfAKh8cKysZZ-WKzLi_LAVHzEBPhbvds6pVBvmEpFw0u-kS04uXwA891h2-bsNNg_79TaRHUIJjd0lG_aR3LB0/s1600/picturesize.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiY3I5mnlVSSzh8zGJ1F4nSkNU1LI6uBUnQCBUOKh5GzPfCtdHh8TbV7cfAKh8cKysZZ-WKzLi_LAVHzEBPhbvds6pVBvmEpFw0u-kS04uXwA891h2-bsNNg_79TaRHUIJjd0lG_aR3LB0/s1600/picturesize.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
Таким образом, можно изменять отображение одного и того же поля в зависимости от представления. Это нередко пригождается на практике, чтобы &quot;зафиксировать&quot; режим отображения поля для кастомизированного представления, чтобы вне зависимости от того что пользователь может поменять некоторые настройки для поля через веб-интерфейс, это поле отображалось бы в нашем представлении именно так, как нужно.&lt;br /&gt;
&lt;br /&gt;
Еще один атрибут, специфичный для SP2013, о котором хотелось бы упомянуть - это &lt;b&gt;AllowGridEditing&lt;/b&gt;. Он позволяет сделать ту или иную колонку нередактируемой в режиме Grid в рамках данного представления. Выглядит полезно, но будьте осторожны: ограничение редактирования такого рода запретами ненадежно, всегда можно будет изменить это поле куском JS через Client Object Model. О том, &lt;a href=&quot;http://omlin.blogspot.fi/2013/02/sharepoint-permissions.html&quot;&gt;как правильно управлять разрешениями и доступом в SharePoint&lt;/a&gt;, у меня есть отдельная статья.&lt;br /&gt;
&lt;br /&gt;
Еще раз напомню: все эти атрибуты как правило доступны в виде свойств объекта SPField, т.е. их можно задавать и на уровне поля, для всех представлений сразу.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Другие атрибуты&lt;/h3&gt;
&lt;br /&gt;
Есть для элементов ViewFields/FieldRef и другие атрибуты. Например, &lt;a href=&quot;http://gandjustas.blogspot.fi/2012/06/3-sharepoint_14.html&quot;&gt;атрибуты &lt;strong&gt;Len&lt;/strong&gt; и &lt;strong&gt;MoreText&lt;/strong&gt;&lt;/a&gt;, нужные для обрезания текста...&lt;br /&gt;
&lt;br /&gt;
Еще один атрибут, тоже иногда пригождающийся - это &lt;strong&gt;AutoHyperLink&lt;/strong&gt;. Он позволяет внутри обычного текстового поля разрешить абсолютные URL-ссылки. Результат выглядит примерно так:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQDkkyaHQ_7e6aVbyELzB_b8YG870w4vRXWivAVDqraHhzFSfajACbDOrLRVsfRHGbpFouylmWL1qV-vtw27DBjZqTtrqCMm6gqv1sYJhdVHtJlmkKnQTAYRyIr-Rr12fUsnhXqmxVZL4/s1600/autohyperlinks.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQDkkyaHQ_7e6aVbyELzB_b8YG870w4vRXWivAVDqraHhzFSfajACbDOrLRVsfRHGbpFouylmWL1qV-vtw27DBjZqTtrqCMm6gqv1sYJhdVHtJlmkKnQTAYRyIr-Rr12fUsnhXqmxVZL4/s1600/autohyperlinks.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Иными словами, ссылки, помещенные внутрь текста, становятся кликабельными. Повторюсь, работает это только&amp;nbsp;для обычных текстовых полей.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Как задать атрибуты ViewFields программно?&lt;/h3&gt;
&lt;br /&gt;
Как я уже упоминал выше, через SPView.ViewFields задать эти атрибуты нельзя. Что же делать?&lt;br /&gt;
&lt;br /&gt;
Очевидно, решение - это попробовать как-то передать в SPView кусок View XML. К сожалению, напрашивающийся для этого метод&amp;nbsp;SetViewXml попросту не работает - проглатывает любой поданный ему XML, но после Update изменения не сохраняются в БД.&lt;br /&gt;
&lt;br /&gt;
Впрочем, если тщательно пошарить в MSDN, вы обнаружите, что &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.spview.spview.aspx&quot;&gt;конструктор SPView&lt;/a&gt; принимает XmlDocument, что практически то что нужно! Однако, метод Update на созданном таким образом SPView, как ни странно, не работает!... Решение этой проблемы можно найти там же в MSDN, в секции Remarks:&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;Use the &lt;b&gt;Clone &lt;/b&gt;method on the constructed view object to add the view to collection of views for the list.&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
Кто бы мог подумать! Создаем SPView используя конструктор, а потом его клонируем, и вот тогда уже можно сохранять. Система нипель, блин :)&lt;br /&gt;
&lt;br /&gt;
Вот вам рабочий код:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;code&quot;&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;var &lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;doc = &lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;new &lt;/span&gt;&lt;span style=&quot;background: white; color: #2b91af;&quot;&gt;XmlDocument&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;();
doc.LoadXml(&lt;/span&gt;&lt;span style=&quot;background: white; color: #a31515;&quot;&gt;&quot;&amp;lt;View ...&amp;gt;...&amp;lt;/View&amp;gt;&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;background: white; color: green;&quot;&gt;// or load from file: doc.Load(&quot;myview.xml&quot;);
&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;var &lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;tempView = &lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;new &lt;/span&gt;&lt;span style=&quot;background: white; color: #2b91af;&quot;&gt;SPView&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;(list, doc);
&lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;var &lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;view = tempView.Clone(&lt;/span&gt;&lt;span style=&quot;background: white; color: #a31515;&quot;&gt;&quot;My view&quot;&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;, 30, &lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;background: white; color: blue;&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;background: white; color: black;&quot;&gt;);
view.Update();&lt;/span&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;h3&gt;
Заключение&lt;/h3&gt;
Создание кастомизированного представления списка - это частая потребность. Поэтому важно уметь управлять представлением и его полями в полной мере. Надеюсь, описанные мной здесь, по большей части малоизвестные атрибуты элементов ViewFields помогут сделать ваши представления лучше. Удачи!</content><link rel='replies' type='application/atom+xml' href='http://omlin.blogspot.com/feeds/208863958862836888/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://omlin.blogspot.com/2013/04/viewfields-fieldref-attributes.html#comment-form' title='Комментарии: 4'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/208863958862836888'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/70467739252625072/posts/default/208863958862836888'/><link rel='alternate' type='text/html' href='http://omlin.blogspot.com/2013/04/viewfields-fieldref-attributes.html' title='Атрибуты ViewFields'/><author><name>Andrei</name><uri>http://www.blogger.com/profile/13548051158654215855</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwlluJBA3y6lxV23dAEL3j9K692R4lY2ggmGXmyypkvvUdL0oK_XnGpuqgCHJBtomRFydbMW1NYloDBjLrOWwy9qNLH3fQMQRJoZuC772vEIzPzymFAMG7O4-Qp-RuIMpc5Fjf5p_PIro/s72-c/explicit.png" height="72" width="72"/><thr:total>4</thr:total></entry></feed>