<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title><![CDATA[microgeek]]></title>
    <link>http://microgeek.ru/</link>
    <description><![CDATA[Последние записи блогов]]></description>
    <language>ru-RU</language>
    <lastBuildDate>Sat, 04 Feb 2012 23:55:01 UT</lastBuildDate>
    <generator><![CDATA[bitrix::blog.rss]]></generator>
    <docs>http://cyber.law.harvard.edu/rss/rss.html</docs>
    <atom:link href="http://microgeek.ru/" rel="self" type="application/rss+xml" />
    <item>
      <title><![CDATA[Стань ближе к звездам с World Wide Telescope]]></title>
      <link>http://microgeek.ru/blogs/conf/1732/</link>
      <description><![CDATA[<p>Microsoft Research приглашает всех желающих принять участие в World Wide Telescope Day, который пройдет 9 февраля 2012 года в Государственном астрономическом институте им. П.К.Штернберга МГУ.</p> <p>Мероприятие проводится для учителей, астрономов-любителей, студентов, аспирантов, ученых – всех тех, кого объединяет непреодолимая тяга к звездам и интерес к астрономии.</p> <p>Программа мероприятия включает как теоретическую, так и практическую части. Участники узнают про уникальный проект виртуального телескопа из рассказа Старшего руководителя исследовательских программ Microsoft Research Йан Шу (Yan Xu), а также услышат выступление ведущего российского астронома, академика Анатолия Черепащука. На практическом занятии каждый сможет попробовать себя в создании тура по звездному небу – интерактивной презентации с помощью World Wide Telescope (WWT). Кроме того, все участники оценят возможности навигации по звездным просторам в формате 3D.</p> <p>Виртуальный телескоп WWT позволяет детально разглядеть планеты Солнечной системы и Землю, узнать созвездия и положение звезд. Проект WWT содержит множество туров, посвящённых рассказам об интереснейших объектах во вселенной, он также позволяет добавлять собственные данные и самостоятельно создавать увлекательные туры. Виртуальный телескоп представляет определенный интерес для ученых как средство обмена научными знаниями, кроме того, это полезный помощник преподавателей, школьников, студентов, астрономов-любителей.</p> <p>Участие в мероприятии свободное. Более подробную информацию о World Wide Telescope Day можно посмотреть на <!--noindex--><a href="http://www.astronet.ru/db/msg/1255677" rel="nofollow">сайте мероприятия</a><!--/noindex-->. </p>]]></description>
      <category><![CDATA[microsoft research]]></category>
      <guid isPermaLink="false">urn:bitrix:blog:post:1732</guid>
      <pubDate>Thu, 02 Feb 2012 08:48:05 UT</pubDate>
      <dc:creator><![CDATA[Vladimir Yunev]]></dc:creator>
    </item>
    <item>
      <title><![CDATA[SharePoint для интернет-сайтов. Брендинг]]></title>
      <link>http://microgeek.ru/blogs/dplotnikov/1731/</link>
      <description><![CDATA[<p>Это продолжение цикла статей, посвященного SharePoint для интернет-сайтов. Первую главу вы можете найти по следующей ссылке: </p> <ul><li><!--noindex--><a href="https://dplotnikov.wordpress.com/2012/01/24/sharepoint-для-интернет-сайтов-введение/" rel="nofollow">SharePoint для интернет-сайтов. Введение</a><!--/noindex--></li>
 </ul> <p>В прошлой статье мы посмотрели веб-сайты, созданные с помощью SharePoint, поняли различия интранет и интернет-сайтов, а также разобрались с лицензированием. </p> <p>В этой статье мы рассмотрим: </p> <ul><li>Структура сайта</li>
 <li>Главные страницы (Master Pages)</li>
 <ul><ul><li>SharePoint Designer</li>
 </ul>
 </ul>
 <li>Макет страницы</li>
 </ul> <h4>Структура сайта</h4> <p>Итак, начнем работу с создания сайта на основе шаблона публикации (рис. 1). </p> <p><img src="http://dplotnikov.files.wordpress.com/2012/01/image2.png" border="0"/> </p> <p>Рис. 1. Внешний вид сайта, созданного из шаблона публикации </p> <p>Как мы уже говорили ранее, продумайте структуру сайта. По умолчанию в сайт включено немного страниц (рис. 2), поэтому лучше сразу подумать, как будут храниться новые страницы. Можно использовать папки, называя их в зависимости от разделов вашего сайта. </p> <p><img src="http://dplotnikov.files.wordpress.com/2012/01/image3.png" border="0"/> </p> <p>Рис. 2. Структура сайта </p> <p>После планирования структуры сайта переходите к планированию внешнего вида страниц. При этом нужно понимать, какие возможности предоставляет SharePoint (указаны по возрастанию сложности): </p> <p>1. Возможности &#171;из коробки&#187; - изменять конент в браузере, используя при этом встроенный WYSIWYG-редактор (открывается при редактировании страницы); </p> <p>2. Встроенные темы – возможность изменения цветовой схемы сайта. Также можно создать цветовую схему (рис. 3); </p> <p><img src="http://dplotnikov.files.wordpress.com/2012/01/image4.png" border="0"/> </p> <p>Рис. 3. Меню выбора цветовой схемы сайта </p> <p>3. Встроенные темы и главная страница – на основе главной страницы можно создать собственную главную страницу и поработать с элементами на ней, а также со стилями; </p> <p>4. Возможность создать дизайн любой сложности – в этом случае также ведется работа над созданием главной страницы и стилей, но уже профессиональными веб-студиями (пример хорошего дизайна - <!--noindex--><a href="http://ferrari.com/" rel="nofollow">http://ferrari.com/</a><!--/noindex-->) </p> <p>Рассмотрим структуры страницы и поймем, что нужно сделать дальше. </p> <h4>Главные страницы (Master Pages)</h4> <p>Если говорить про структуру страницы в целом, то она состоит из главной страницы и контента (рис. 4) Таким образом, основная работа при создании веб-сайта с использованием SharePoint – создание главной страницы. </p> <p><img src="http://dplotnikov.files.wordpress.com/2012/01/image5.png" border="0"/> </p> <p>Рис. 4. Общая структура страницы </p> <p>На рис. 5 изображена структура страницы SharePoint. Как вы можете видеть, главная страница включает ленту (которую можно скрыть), заголовок, область для контента и зону для панели разработчика. Безусловно, вы можете создать главную страницу, которая по структуре может не соответствовать изображенной на рисунке ниже. </p> <p><img src="http://dplotnikov.files.wordpress.com/2012/01/image6.png" border="0"/> </p> <p>Рис. 5. Структура страницы </p> <p>Далее рассмотрим, как можно создать главную страницу, для данной задачи идеально подходит SharePoint Designer 2010, предоставляющий больше возможностей для работы с SharePoint, чем браузер. В частности, можно поработать с кодом страниц. </p> <h5>SharePoint Designer</h5> <p>Как вы знаете, в SharePoint 2010 есть следующие типы главных страниц </p> <ul><li><i>default</i><i>.</i><i>master</i> – страница, оставшаяся от SharePoint 2007. <i>Действия сайта</i> в правой части, отсутствует лента;</li>
 <li><i>v</i><i>4.</i><i>master</i> – основная страница для SharePoint 2010;</li>
 <li><i>minimal</i><i>.</i><i>master</i> – страница почти ничего не содержит, используется для приложения поиска и Office Web Apps. Навигация отсутствует;</li>
 <li><i>simple</i><i>.</i><i>master</i> – используется для страниц ошибок и авторизации; </li>
 <li><i>nightandday</i><i>.master</i> – появляется при активации <i>Инфрастуктуры публикации </i><i>SharePoint</i><i> Server</i>.</li>
 </ul> <p>Лучше всего использовать minimal.master. Создайте копию, а дальше работайте с ней в SharePoint Designer 2010, вставляя туда HTML-разметку, CSS или элементы управления. </p> <p>Для работы со стилями в SharePoint Designer на ленте есть вкладка <i>Стиль </i>(рис. 6), функционал которой размещен в четырех группах </p> <ul><li>Главная страница - управление подключениями главных страниц;</li>
 <li>Создание – создание и управление стилями;</li>
 <li>Применение стилей – выбор режима применения стиля;</li>
 <li>Свойства – свойства тега, CSS, страницы или выбранного элемента.</li>
 </ul> <p><img src="http://dplotnikov.files.wordpress.com/2012/01/image7.png" border="0"/> </p> <p>Рис. 6. Вкладка <i>Стиль</i> на ленте SharePoint Designer 2010 </p> <p>После внесения изменений нужно сохранить файл, и опубликовать на портал в качестве основного документа. Для того, чтобы использовалась созданная нами главная страница, нужно указать ее в качестве главной (рис. 7), для чего в <i>параметрах сайта</i> нужно выбрать <i>Главная страница</i>. </p> <p><img src="http://dplotnikov.files.wordpress.com/2012/01/image8.png" border="0"/> </p> <p>Рис. 7. Выбор главной страницы сайта </p> <p>После этого дизайн вашего веб-сайта в зависимости от вложенных усилий станет отличаться от стандартного. </p> <p>Если вы хотите, чтобы контент на страницах располагался не в одном блоке, то придется создать <i>Макет страницы</i>. </p> <h4>Макет страницы</h4> <p>Макет страницы (page layout) – это шаблон для отображения контента. При создании страницы нужно указать ее макет (рис. 8). Как вы видите, в SharePoint уже есть некоторое количество готовых макетов, но при необходимости можно создать свой макет. </p> <p><img src="http://dplotnikov.files.wordpress.com/2012/01/image9.png" border="0"/> </p> <p>Рис. 8. Выбор макета при создании новой страницы </p> <p>Чтобы создать новый макет страницы, создайте новый тип контента, наследуемый от страницы. Для этого типа контента укажите поля, которые в него входят, например, изображение, адрес электронной почты, поле для метаданных (работу с которыми мы будем рассматривать позже) и т.д. </p> <p>После этого перейдите в каталог главных страниц и создайте там новый макет страницы (рис. 9) на основе нашего типа контента. </p> <p><img src="http://dplotnikov.files.wordpress.com/2012/01/image10.png" border="0"/> </p> <p>Рис. 9. Создание нового макета страницы </p> <p>Далее откройте макет (представляет собой ASPX страницу) для редактирования в SharePoint Designer. При этом можете добавить созданные вами поля из типа контента на макет страницы. После работы сохраните файл. Теперь можно создавать новые страницы на основе созданного макета страниц. </p> <p>Итак, в этой статье мы рассмотрели возможности SharePoint для создания брендинга. </p>]]></description>
      <category><![CDATA[SharePoint 2010]]></category>
      <category><![CDATA[брендинг]]></category>
      <category><![CDATA[master pages]]></category>
      <category><![CDATA[page layout]]></category>
      <category><![CDATA[SharePoint Designer 2010]]></category>
      <category><![CDATA[sharepoint для интернет сайтов]]></category>
      <category><![CDATA[sharepoint fis]]></category>
      <category><![CDATA[sharepoint for internet sites]]></category>
      <guid isPermaLink="false">urn:bitrix:blog:post:1731</guid>
      <pubDate>Tue, 31 Jan 2012 07:11:44 UT</pubDate>
      <dc:creator><![CDATA[Dmitry Plotnikov]]></dc:creator>
    </item>
    <item>
      <title><![CDATA[Доступна запись вебинара "Будущее ASP.NET и Visual Studio 11 для веб-разработчиков"]]></title>
      <link>http://microgeek.ru/blogs/aspnet/1730/</link>
      <description><![CDATA[<p><img src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-44-06-metablogapi/5126.image_5F00_662C9C7C.png" alt="image" title="image" width="461px" height="329px" border="0"/></p> <p>26 января состоялся <!--noindex--><a href="http://blogs.msdn.com/b/vyunev/archive/2012/01/19/asp-net-visual-studio-11.aspx" rel="nofollow">бесплатный вебинар</a><!--/noindex--> на тему нововведений веб-платформе Microsoft и среде разработки Visual Studio 11 для веб-разработчиков. Спасибо всем участникам вебинара (вас было более 170 человек), в том числе за интересные вопросы после сессии.</p> <p>Я рад сообщить, что для загрузки доступно видео вебинара, которое вы можете легко скачать по следующей ссылке “<!--noindex--><a href="https://www206.livemeeting.com/cc/wwe_uk/view?cn=guest&amp;id=1032503722&amp;pw=7099F547" rel="nofollow">Нововведения в Visual Studio 2011 для веб-разработчиков</a><!--/noindex-->”. Видео доступно как для онлайн-просмотра, так и для загрузки (~40 Mb, wmv). </p> <p>Кроме того, вы можете загрузить файл презентации (pptx) по <!--noindex--><a href="http://docs.com/HLTT" rel="nofollow">следующей ссылке</a><!--/noindex--> с сайта docs.com.</p> <p>В рамках вебинара были рассмотрены следующие основные темы:</p> <ul> <li>ASP.NET WebForms 4.5 – ответ на ваши запросы </li>
 <li>ASP.NET MVC 4 и тренды мобильного веба </li>
 <li>Visual Studio 11, что нового и удобного для веб-разработчика? </li>
 </ul> <p>Пользуясь случаем, хочу еще раз извиниться у участников за задержку с выступлением. Мы работаем над тем, чтобы подобных задержек в будущем не происходило.</p> ]]></description>
      <category><![CDATA[asp.net]]></category>
      <category><![CDATA[asp.net mvc]]></category>
      <category><![CDATA[visual studio]]></category>
      <category><![CDATA[asp.net webforms]]></category>
      <category><![CDATA[вебинары]]></category>
      <guid isPermaLink="false">urn:bitrix:blog:post:1730</guid>
      <pubDate>Mon, 30 Jan 2012 09:46:24 UT</pubDate>
      <dc:creator><![CDATA[Vladimir Yunev]]></dc:creator>
    </item>
    <item>
      <title><![CDATA[ASP.NET: Пара сценариев отображения данных в GridView]]></title>
      <link>http://microgeek.ru/blogs/tym32167/1729/</link>
      <description><![CDATA[<div style="text-align: left">Здравствуйте. Сегодня поговорим о веб-разработке. Несмотря на то, что популярность <!--noindex--><a href="http://www.asp.net/mvc" rel="nofollow">MVC</a><!--/noindex--> растет очень быстро, <!--noindex--><a href="http://www.asp.net/web-forms" rel="nofollow">Web Forms</a><!--/noindex--> ещё никто не отменял. К тому же много приложений написано с использованием <!--noindex--><a href="http://www.asp.net/web-forms" rel="nofollow">Web Forms</a><!--/noindex-->, да и уже написанные приложения требуют поддержки. И если простейшие контролы (например, <!--noindex--><a href="http://msdn.microsoft.com/ru-ru/library/system.web.ui.webcontrols.textbox.aspx" rel="nofollow">TextBox</a><!--/noindex-->) у новичков вопросов, как правило, не вызывают, то сориентироваться в чем-то более сложном уже проблема. <br/>
В данном посте я расскажу в общих чертах, как использовать контрол <!--noindex--><a href="http://msdn.microsoft.com/ru-ru/library/system.web.ui.webcontrols.gridview.aspx" rel="nofollow">GridView</a><!--/noindex--> для работы со списком или специализированным источником данных. Предупреждаю сразу, тема не новая и статья ориентирована на начинающих разработчиков. <br/>
Поехали.<br/>
<a name="more" rel="nofollow"></a><br/>
<br/>
Начнем с теории. Класс <!--noindex--><a href="http://msdn.microsoft.com/ru-ru/library/system.web.ui.webcontrols.gridview.aspx" rel="nofollow">GridView</a><!--/noindex--> <table class="blog-quote"><tr><th>Цитата</th></tr><tr><td>Отображает значения источника данных в таблице, где каждый столбец представляет поле, а каждая строка — запись. Элемент управления GridView позволяет выбирать, сортировать и изменять эти записи.</td></tr></table>Его можно связывать с элементами-источниками данных (например, наследниками <!--noindex--><a href="http://msdn.microsoft.com/ru-ru/library/system.web.ui.datasourcecontrol.aspx" rel="nofollow">DataSourceControl</a><!--/noindex-->), а можно просто отображать перечисляемые списки, указав значение свойства <!--noindex--><a href="http://msdn.microsoft.com/ru-ru/library/system.web.ui.webcontrols.basedataboundcontrol.datasource.aspx" rel="nofollow">DataSource</a><!--/noindex-->. Начнем с последнего.<br/>
<br/>
Итак, задача: Имеется страница, на которой расположен GridView, и список, который нужно на этой странице формировать и иметь возможность его изменять (то есть добавлять/удалять элементы). Список хранится только на странице. <br/>
<br/>
Порядок действий:<br/>
<ul><li>Создаём веб-приложение</li>
 <li>Удаляем с домашней страницы всё лишнее (необязательно)</li>
 <li>Создаём страницу GridViewList.aspx, указываем для неё мастер страницу</li>
 <li>Добавляем в меню пункт со ссылкой на GridViewList.aspx</li>
 </ul><div style="text-align: center"><!--noindex--><a href="http://4.bp.blogspot.com/-WX35UfBzvc8/TyAtzVQUrpI/AAAAAAAAC9Q/A4C5G1r2hW4/s1600/2.PNG" rel="nofollow" style="margin-left: 1em; margin-right: 1em"><img src="http://4.bp.blogspot.com/-WX35UfBzvc8/TyAtzVQUrpI/AAAAAAAAC9Q/A4C5G1r2hW4/s1600/2.PNG" width="600px" border="0"/></a><!--/noindex--></div>Отлично, полигон для действий готов. Класс-объект, с которым мы будем работать, я определил так:<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 3em; padding: 0 0 0 5px"><li>[<span>Serializable</span>]</li>
 <li><span>public</span> <span>class</span> <span>People</span></li>
 <li>{</li>
 <li> [<span>XmlAttribute</span>]</li>
 <li> <span>public</span> <span>int</span> Id { <span>get</span>; <span>set</span>; }</li>
 <li> [<span>XmlAttribute</span>]</li>
 <li> <span>public</span> <span>string</span> FirstName { <span>get</span>; <span>set</span>; }</li>
 <li> [<span>XmlAttribute</span>]</li>
 <li> <span>public</span> <span>string</span> LastName { <span>get</span>; <span>set</span>; }</li>
 <li>}</li>
 </ol></div></div><br/>
Теперь определимся со списком. Во-первых, так как список формируется и изменяется только в рамках этой страницы, я решил хранить его во <!--noindex--><a href="http://msdn.microsoft.com/ru-ru/library/system.web.ui.control.viewstate.aspx" rel="nofollow">ViewState</a><!--/noindex-->. Я просто определил свойство на странице, которое автоматом себя сохраняет.<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>public</span> <span>List</span>&lt;<span>People</span>&gt; Peoples</li>
 <li>{</li>
 <li> <span>get</span></li>
 <li> {</li>
 <li> <span>// Получение ключа для поиска во ViewState. </span></li>
 <li> <span>// hfPeoplesViewState - HiddenField, которое хранит в себе этот ключ</span></li>
 <li> <span>// Это всё сделано только для того, чтобы обеспечить уникальность ключа на странице. </span></li>
 <li> <span>// По идее тут можно было просто написать var str = &quot;Peoples_Key&quot; и всё бы работало</span></li>
 <li> <span>var</span> str = hfPeoplesViewState.Value;</li>
 <li> <span>if</span> (<span>string</span>.IsNullOrEmpty(str))</li>
 <li> {</li>
 <li> <span>// Если ещё ничего не хранит, то создать ключ</span></li>
 <li> hfPeoplesViewState.Value = <span>string</span>.Format(<span>&quot;Peoples_{</span><span>0}</span><span>&quot;</span>, <span>Guid</span>.NewGuid());</li>
 <li> str = hfPeoplesViewState.Value;</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>// Проверяю, если во ViewState ещё нет того списка, что мне нужен - создаю его</span></li>
 <li> <span>if</span> (ViewState[str] == <span>null</span> || !(ViewState[str] <span>is</span> <span>List</span>&lt;<span>People</span>&gt;))</li>
 <li> {</li>
 <li> <span>var</span> peoples = <span>new</span> <span>List</span>&lt;<span>People</span>&gt;</li>
 <li> {</li>
 <li> <span>new</span> <span>People</span> {Id = 1, LastName = <span>&quot;Мурадов&quot;</span>, FirstName = <span>&quot;Артем&quot;}</span>,</li>
 <li> <span>new</span> <span>People</span> {Id = 2, LastName = <span>&quot;Пупкин&quot;</span>, FirstName = <span>&quot;Василий&quot;}</span>,</li>
 <li> <span>new</span> <span>People</span> {Id = 3, LastName = <span>&quot;Елопанов&quot;</span>, FirstName = <span>&quot;Инокентий&quot;}</span></li>
 <li> };</li>
 <li> ViewState[str] = peoples;</li>
 <li> <span>return</span> peoples;</li>
 <li> }</li>
 <li> <span>return</span> ViewState[str] <span>as</span> <span>List</span>&lt;<span>People</span>&gt;;</li>
 <li> }</li>
 <li> <span>set</span></li>
 <li> {</li>
 <li> <span>// Аналогично методу get</span></li>
 <li> <span>var</span> str = hfPeoplesViewState.Value;</li>
 <li> <span>if</span> (<span>string</span>.IsNullOrEmpty(str))</li>
 <li> {</li>
 <li> hfPeoplesViewState.Value = <span>string</span>.Format(<span>&quot;Peoples_{</span><span>0}</span><span>&quot;</span>, <span>Guid</span>.NewGuid());</li>
 <li> str = hfPeoplesViewState.Value;</li>
 <li> }</li>
 <li>&#160;</li>
 <li> ViewState[str] = <span>value</span>;</li>
 <li> }</li>
 <li>}</li>
 </ol></div></div><br/>
Добавим GridView в разметку. По пути также добавим пару текстовых полей и кнопку, для возможности добавления элемента в коллекцию.<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>&lt;</span><span>asp</span><span>:</span><span>TextBox</span> <span>runat</span><span>=&quot;server&quot;</span> <span>ID</span><span>=&quot;tbFirstName&quot;&gt;</span></li>
 <li><span>&lt;/</span><span>asp</span><span>:</span><span>TextBox</span><span>&gt;</span></li>
 <li><span>&lt;</span><span>asp</span><span>:</span><span>TextBox</span> <span>runat</span><span>=&quot;server&quot;</span> <span>ID</span><span>=&quot;tbLastName&quot;&gt;</span></li>
 <li><span>&lt;/</span><span>asp</span><span>:</span><span>TextBox</span><span>&gt;</span></li>
 <li><span>&lt;</span><span>asp</span><span>:</span><span>Button</span> <span>runat</span><span>=&quot;server&quot;</span> <span>OnClick</span><span>=&quot;BtAddPeople&quot;</span> <span>Text</span><span>=&quot;+&quot;</span> <span>/&gt;</span></li>
 <li><span>&lt;</span><span>hr</span> <span>/&gt;</span></li>
 <li><span>&lt;</span><span>asp</span><span>:</span><span>GridView</span> <span>runat</span><span>=&quot;server&quot;</span> <span>ID</span><span>=&quot;gv&quot;</span> <span>AutoGenerateColumns</span><span>=&quot;True&quot;</span> <span>Width</span><span>=&quot;60%&quot;&gt;</span></li>
 <li> <span>&lt;</span><span>EmptyDataTemplate</span><span>&gt;</span></li>
 <li> Записей нет<span>&lt;/</span><span>EmptyDataTemplate</span><span>&gt;</span></li>
 <li><span>&lt;/</span><span>asp</span><span>:</span><span>GridView</span><span>&gt;</span></li>
 </ol></div></div><br/>
В обработчике событий<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 3em; padding: 0 0 0 5px"><li><span>protected</span> <span>void</span> Page_Load(<span>object</span> sender, <span>EventArgs</span> e)</li>
 <li>{</li>
 <li> <span>if</span> (!IsPostBack)</li>
 <li> {</li>
 <li> gv.DataSource = Peoples;</li>
 <li> gv.DataBind();</li>
 <li> }</li>
 <li>}</li>
 <li>&#160;</li>
 <li><span>protected</span> <span>void</span> BtAddPeople(<span>object</span> sender, <span>EventArgs</span> e)</li>
 <li>{</li>
 <li> <span>if</span> (!<span>string</span>.IsNullOrEmpty(tbFirstName.Text) &amp;&amp; !<span>string</span>.IsNullOrEmpty(tbLastName.Text))</li>
 <li> {</li>
 <li> <span>var</span> id = Peoples.Count &gt; 0 ? Peoples.Max(x =&gt; x.Id) + 1 : 1;</li>
 <li> <span>var</span> p = <span>new</span> <span>People</span></li>
 <li> {</li>
 <li> Id = id,</li>
 <li> FirstName = tbFirstName.Text,</li>
 <li> LastName = tbLastName.Text</li>
 <li> };</li>
 <li> Peoples.Add(p);</li>
 <li> UpdateGrid();</li>
 <li> }</li>
 <li>}</li>
 <li>&#160;</li>
 <li><span>private</span> <span>void</span> UpdateGrid()</li>
 <li>{</li>
 <li> gv.DataSource = Peoples;</li>
 <li> gv.DataBind();</li>
 <li>}</li>
 </ol></div></div><br/>
Окей, теперь при первой загрузке страницы, у нас будет заполняться GridView. А при добавлении элемента в коллекцию, GridView будет обновляться. Вот как это выглядит:<br/>
<div style="text-align: center"><!--noindex--><a href="http://3.bp.blogspot.com/-jGERSv83oD8/TyAzH67l0uI/AAAAAAAAC9c/LfAqSYmwSj8/s1600/3.PNG" rel="nofollow" style="margin-left: 1em; margin-right: 1em"><img src="http://3.bp.blogspot.com/-jGERSv83oD8/TyAzH67l0uI/AAAAAAAAC9c/LfAqSYmwSj8/s1600/3.PNG" border="0"/></a><!--/noindex--></div><br/>
Добавление работает, но у нас нет ни сортировки, ни редактирования, ни удаления, да ещё и включена автогенерация полей. Вот с последнего и начнем. Отключаем автогенерацию, указываем нужные нам поля, разрешаем сортировку (<!--noindex--><a href="http://msdn.microsoft.com/ru-ru/library/system.web.ui.webcontrols.gridview.columns.aspx" rel="nofollow">список возможных полей</a><!--/noindex-->):<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>&lt;</span><span>asp</span><span>:</span><span>GridView</span> <span>runat</span><span>=&quot;server&quot;</span> <span>ID</span><span>=&quot;gv&quot;</span> <span>AutoGenerateColumns</span><span>=&quot;False&quot;</span> <span>Width</span><span>=&quot;60%&quot;</span> <span>AllowSorting</span><span>=&quot;True&quot;&gt;</span></li>
 <li> <span>&lt;</span><span>Columns</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>asp</span><span>:</span><span>BoundField</span> <span>HeaderText</span><span>=&quot;ИД&quot;</span> <span>DataField</span><span>=&quot;Id&quot;</span> <span>SortExpression</span><span>=&quot;Id&quot;</span> <span>ReadOnly</span><span>=&quot;True&quot;&gt;</span></li>
 <li> <span>&lt;</span><span>ItemStyle</span> <span>Width</span><span>=&quot;5%&quot;&gt;&lt;/</span><span>ItemStyle</span><span>&gt;</span></li>
 <li> <span>&lt;/</span><span>asp</span><span>:</span><span>BoundField</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>asp</span><span>:</span><span>BoundField</span> <span>HeaderText</span><span>=&quot;Имя&quot;</span> <span>DataField</span><span>=&quot;FirstName&quot;</span> <span>SortExpression</span><span>=&quot;FirstName&quot;&gt;</span></li>
 <li> <span>&lt;</span><span>ItemStyle</span> <span>Width</span><span>=&quot;40%&quot;&gt;&lt;/</span><span>ItemStyle</span><span>&gt;</span></li>
 <li> <span>&lt;/</span><span>asp</span><span>:</span><span>BoundField</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>asp</span><span>:</span><span>BoundField</span> <span>HeaderText</span><span>=&quot;Фамилия&quot;</span> <span>DataField</span><span>=&quot;LastName&quot;</span> <span>SortExpression</span><span>=&quot;LastName&quot;&gt;</span></li>
 <li> <span>&lt;</span><span>ItemStyle</span> <span>Width</span><span>=&quot;40%&quot;&gt;&lt;/</span><span>ItemStyle</span><span>&gt;</span></li>
 <li> <span>&lt;/</span><span>asp</span><span>:</span><span>BoundField</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>asp</span><span>:</span><span>CommandField</span> <span>ShowEditButton</span><span>=&quot;True&quot;</span> <span>ShowDeleteButton</span><span>=&quot;True&quot;</span> <span>ShowCancelButton</span><span>=&quot;True&quot;&gt;</span></li>
 <li> <span>&lt;</span><span>ItemStyle</span> <span>Width</span><span>=&quot;15%&quot;&gt;&lt;/</span><span>ItemStyle</span><span>&gt;</span></li>
 <li> <span>&lt;/</span><span>asp</span><span>:</span><span>CommandField</span><span>&gt;</span></li>
 <li> <span>&lt;/</span><span>Columns</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>EmptyDataTemplate</span><span>&gt;</span></li>
 <li> Записей нет<span>&lt;/</span><span>EmptyDataTemplate</span><span>&gt;</span></li>
 <li><span>&lt;/</span><span>asp</span><span>:</span><span>GridView</span><span>&gt;</span></li>
 </ol></div></div><div style="text-align: center"><!--noindex--><a href="http://2.bp.blogspot.com/-HtuL9fFDUt0/TyA1hW-qReI/AAAAAAAAC9o/4rGxgPf4hGo/s1600/4.PNG" rel="nofollow" style="margin-left: 1em; margin-right: 1em"><img src="http://2.bp.blogspot.com/-HtuL9fFDUt0/TyA1hW-qReI/AAAAAAAAC9o/4rGxgPf4hGo/s1600/4.PNG" border="0"/></a><!--/noindex--></div>Теперь у нас есть кнопки, для того, чтобы сортировать, редактировать или удалять. Но только этого функционала пока нет. GridView не может самостоятельно править нашу коллекцию. Но это не беда, нам достаточно подписаться на нужные нам события и реализовать всё самим. Для редактирования нужны следующие события: OnRowEditing=&quot;GvEditing&quot; OnRowUpdating=&quot;GvUpdating&quot; OnRowCancelingEdit=&quot;GvCancelingEdit&quot;, для сортировки OnSorting=&quot;GvSorting&quot;, для удаления OnRowDeleting=&quot;GvDeleting&quot;. <br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>&lt;</span><span>asp</span><span>:</span><span>GridView</span> <span>runat</span><span>=&quot;server&quot;</span> <span>ID</span><span>=&quot;gv&quot;</span> <span>AllowSorting</span><span>=&quot;True&quot;</span> <span>OnSorting</span><span>=&quot;GvSorting&quot;</span> <span>OnRowEditing</span><span>=&quot;GvEditing&quot;</span></li>
 <li> <span>OnRowUpdating</span><span>=&quot;GvUpdating&quot;</span> <span>OnRowCancelingEdit</span><span>=&quot;GvCancelingEdit&quot;</span> <span>OnRowDeleting</span><span>=&quot;GvDeleting&quot;</span></li>
 <li> <span>DataKeyNames</span><span>=&quot;Id&quot;</span> <span>AutoGenerateColumns</span><span>=&quot;False&quot;</span> <span>Width</span><span>=&quot;60%&quot;</span> <span>&gt;</span></li>
 <li> <span>&lt;</span><span>Columns</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>asp</span><span>:</span><span>BoundField</span> <span>HeaderText</span><span>=&quot;ИД&quot;</span> <span>DataField</span><span>=&quot;Id&quot;</span> <span>SortExpression</span><span>=&quot;Id&quot;</span> <span>ReadOnly</span><span>=&quot;True&quot;&gt;</span></li>
 <li> <span>&lt;</span><span>ItemStyle</span> <span>Width</span><span>=&quot;5%&quot;&gt;&lt;/</span><span>ItemStyle</span><span>&gt;</span></li>
 <li> <span>&lt;/</span><span>asp</span><span>:</span><span>BoundField</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>asp</span><span>:</span><span>BoundField</span> <span>HeaderText</span><span>=&quot;Имя&quot;</span> <span>DataField</span><span>=&quot;FirstName&quot;</span> <span>SortExpression</span><span>=&quot;FirstName&quot;&gt;</span></li>
 <li> <span>&lt;</span><span>ItemStyle</span> <span>Width</span><span>=&quot;40%&quot;&gt;&lt;/</span><span>ItemStyle</span><span>&gt;</span></li>
 <li> <span>&lt;/</span><span>asp</span><span>:</span><span>BoundField</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>asp</span><span>:</span><span>BoundField</span> <span>HeaderText</span><span>=&quot;Фамилия&quot;</span> <span>DataField</span><span>=&quot;LastName&quot;</span> <span>SortExpression</span><span>=&quot;LastName&quot;&gt;</span></li>
 <li> <span>&lt;</span><span>ItemStyle</span> <span>Width</span><span>=&quot;40%&quot;&gt;&lt;/</span><span>ItemStyle</span><span>&gt;</span></li>
 <li> <span>&lt;/</span><span>asp</span><span>:</span><span>BoundField</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>asp</span><span>:</span><span>CommandField</span> <span>ShowEditButton</span><span>=&quot;True&quot;</span> <span>ShowDeleteButton</span><span>=&quot;True&quot;</span> <span>ShowCancelButton</span><span>=&quot;True&quot;&gt;</span></li>
 <li> <span>&lt;</span><span>ItemStyle</span> <span>Width</span><span>=&quot;15%&quot;&gt;&lt;/</span><span>ItemStyle</span><span>&gt;</span></li>
 <li> <span>&lt;/</span><span>asp</span><span>:</span><span>CommandField</span><span>&gt;</span></li>
 <li> <span>&lt;/</span><span>Columns</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>EmptyDataTemplate</span><span>&gt;</span></li>
 <li> Записей нет<span>&lt;/</span><span>EmptyDataTemplate</span><span>&gt;</span></li>
 <li><span>&lt;/</span><span>asp</span><span>:</span><span>GridView</span><span>&gt;</span></li>
 </ol></div></div><br/>
Вот код для сортировки<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 3em; padding: 0 0 0 5px"><li><span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li><span>///</span><span> Возникает при сортировке в гриде.</span></li>
 <li><span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li><span>protected</span> <span>void</span> GvSorting(<span>object</span> sender, <span>GridViewSortEventArgs</span> e)</li>
 <li>{</li>
 <li> <span>var</span> p = Peoples;</li>
 <li>&#160;</li>
 <li> <span>// Необходимо определить, по какому именно полю сортировать</span></li>
 <li> <span>if</span> (e.SortExpression == <span>&quot;LastName&quot;</span>)</li>
 <li> {</li>
 <li> <span>// используем вспомогательный метод Sort</span></li>
 <li> p = Sort(<span>&quot;LastName&quot;</span>, list =&gt; list.OrderBy(x =&gt; x.LastName).ToList(),</li>
 <li> list =&gt; list.OrderByDescending(x =&gt; x.LastName).ToList(), p);</li>
 <li> }</li>
 <li> <span>if</span> (e.SortExpression == <span>&quot;FirstName&quot;</span>)</li>
 <li> {</li>
 <li> p = Sort(<span>&quot;FirstName&quot;</span>, list =&gt; list.OrderBy(x =&gt; x.FirstName).ToList(),</li>
 <li> list =&gt; list.OrderByDescending(x =&gt; x.FirstName).ToList(), p);</li>
 <li> }</li>
 <li> <span>if</span> (e.SortExpression == <span>&quot;Id&quot;</span>)</li>
 <li> {</li>
 <li> p = Sort(<span>&quot;Id&quot;</span>, list =&gt; list.OrderBy(x =&gt; x.Id).ToList(),</li>
 <li> list =&gt; list.OrderByDescending(x =&gt; x.Id).ToList(), p);</li>
 <li> }</li>
 <li>&#160;</li>
 <li> Peoples = p;</li>
 <li> <span>// обновление грида</span></li>
 <li> UpdateGrid();</li>
 <li>}</li>
 <li>&#160;</li>
 <li><span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li><span>///</span><span> Вспомогательный метод для сортировки</span></li>
 <li><span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li><span>private</span> <span>List</span>&lt;<span>People</span>&gt; Sort(<span>string</span> column, <span>Func</span>&lt;<span>List</span>&lt;<span>People</span>&gt;, <span>List</span>&lt;<span>People</span>&gt;&gt; ascFunc, <span>Func</span>&lt;<span>List</span>&lt;<span>People</span>&gt;, <span>List</span>&lt;<span>People</span>&gt;&gt; descFunc, <span>List</span>&lt;<span>People</span>&gt; data)</li>
 <li>{</li>
 <li> <span>List</span>&lt;<span>People</span>&gt; result;</li>
 <li> <span>// Если в прошлвй раз была сортировка по этому же полю</span></li>
 <li> <span>if</span> (hfLastSortFieldState.Value == column)</li>
 <li> {</li>
 <li> <span>// смотрим, в каком направлении была сортировка в прошлвй раз и сортируем в другом</span></li>
 <li> result = hfLastSortDirectionState.Value != <span>&quot;ASC&quot;</span> ? ascFunc(data) : descFunc(data);</li>
 <li> <span>// сохраняем колонку и направление сортировки</span></li>
 <li> hfLastSortDirectionState.Value = hfLastSortDirectionState.Value != <span>&quot;ASC&quot;</span> ? <span>&quot;ASC&quot;</span> : <span>&quot;DESC&quot;</span>;</li>
 <li> hfLastSortFieldState.Value = column;</li>
 <li> }</li>
 <li> <span>else</span></li>
 <li> {</li>
 <li> <span>// Если это поле ещё не сортировано, сортируем по возрастанию</span></li>
 <li> result = ascFunc(data);</li>
 <li> <span>// сохраняем колонку и направление сортировки</span></li>
 <li> hfLastSortDirectionState.Value = <span>&quot;ASC&quot;</span>;</li>
 <li> hfLastSortFieldState.Value = column;</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>return</span> result;</li>
 <li>}</li>
 </ol></div></div><br/>
Код для редактирования и удаления<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 3em; padding: 0 0 0 5px"><li><span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li><span>///</span><span> Событие удаления элемента. Поле Id попадает в набор ключей, </span></li>
 <li><span>///</span><span> так как в гриде указано DataKeyNames=&quot;Id&quot;</span></li>
 <li><span>///</span><span> Нам осталось только определить ключ и убрать элемент с этим ключем из коллекции </span></li>
 <li><span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li><span>protected</span> <span>void</span> GvDeleting(<span>object</span> sender, <span>GridViewDeleteEventArgs</span> e)</li>
 <li>{</li>
 <li> <span>int</span> id;</li>
 <li> <span>// Определяем идентификатор</span></li>
 <li> <span>if</span> (<span>int</span>.TryParse(<span>string</span>.Format(<span>&quot;{</span><span>0}</span><span>&quot;</span>, e.Keys[<span>&quot;Id&quot;</span>]), <span>out</span> id))</li>
 <li> {</li>
 <li> <span>// Убираем из списка</span></li>
 <li> Peoples = Peoples.Where(x =&gt; x.Id != id).ToList();</li>
 <li> <span>// обновляем грид</span></li>
 <li> UpdateGrid();</li>
 <li> }</li>
 <li>}</li>
 <li>&#160;</li>
 <li><span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li><span>///</span><span> Событие возникает, когда пользователь начинает редактировать строку. </span></li>
 <li><span>///</span><span> Необходимо просто указать гриду индекс редактируемой строки и обновить грид</span></li>
 <li><span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li><span>protected</span> <span>void</span> GvEditing(<span>object</span> sender, <span>GridViewEditEventArgs</span> e)</li>
 <li>{</li>
 <li> gv.EditIndex = e.NewEditIndex;</li>
 <li> UpdateGrid();</li>
 <li>}</li>
 <li>&#160;</li>
 <li><span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li><span>///</span><span> Событие возникает, когда пользователь обновляет строку. </span></li>
 <li><span>///</span><span> Необходимо определить Id строки, получить элемент по этому Id, обновить поля и обновить грид </span></li>
 <li><span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li><span>protected</span> <span>void</span> GvUpdating(<span>object</span> sender, <span>GridViewUpdateEventArgs</span> e)</li>
 <li>{</li>
 <li> <span>int</span> id;</li>
 <li> <span>if</span> (<span>int</span>.TryParse(<span>string</span>.Format(<span>&quot;{</span><span>0}</span><span>&quot;</span>, e.Keys[<span>&quot;Id&quot;</span>]), <span>out</span> id))</li>
 <li> {</li>
 <li> Peoples</li>
 <li> .Where(x =&gt; x.Id == id)</li>
 <li> .ToList()</li>
 <li> .ForEach(x =&gt;</li>
 <li> {</li>
 <li> <span>// я использую string.Format, так как </span></li>
 <li> <span>// e.NewValues[&quot;FirstName&quot;] имеет тип object</span></li>
 <li> <span>// и может быть равен null</span></li>
 <li> x.FirstName = <span>string</span>.Format(<span>&quot;{</span><span>0}</span><span>&quot;</span>, e.NewValues[<span>&quot;FirstName&quot;</span>]);</li>
 <li> x.LastName = <span>string</span>.Format(<span>&quot;{</span><span>0}</span><span>&quot;</span>, e.NewValues[<span>&quot;LastName&quot;</span>]);</li>
 <li> });</li>
 <li> gv.EditIndex = -1;</li>
 <li> UpdateGrid();</li>
 <li> }</li>
 <li>}</li>
 <li>&#160;</li>
 <li><span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li><span>///</span><span> Событие возникает, когда пользователь отменяет обновление строки</span></li>
 <li><span>///</span><span> Нужно установить gv.EditIndex = -1; и обновить грид</span></li>
 <li><span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li><span>protected</span> <span>void</span> GvCancelingEdit(<span>object</span> sender, <span>GridViewCancelEditEventArgs</span> e)</li>
 <li>{</li>
 <li> gv.EditIndex = -1;</li>
 <li> UpdateGrid();</li>
 <li>}</li>
 </ol></div></div><br/>
В итоге имеем грид, элементы которого можем удалять, добавлять, редактировать и сортировать.<br/>
<div style="text-align: center"><!--noindex--><a href="http://2.bp.blogspot.com/-6dB9D9wGuWg/TyGAyEtSF9I/AAAAAAAAC-E/LW99q2WssuE/s1600/5.PNG" rel="nofollow" style="margin-left: 1em; margin-right: 1em"><img src="http://2.bp.blogspot.com/-6dB9D9wGuWg/TyGAyEtSF9I/AAAAAAAAC-E/LW99q2WssuE/s1600/5.PNG" border="0"/></a><!--/noindex--></div><br/>
Это всё хорошо, но что делать, если мы работаем с базой данных? В таких случаях можно определять источники данных (например, наследники <!--noindex--><a href="http://msdn.microsoft.com/ru-ru/library/system.web.ui.datasourcecontrol.aspx" rel="nofollow">DataSourceControl</a><!--/noindex-->) и связывать их с гридом. Я приведу пример с использованием <!--noindex--><a href="http://msdn.microsoft.com/ru-ru/library/system.web.ui.webcontrols.objectdatasource.aspx" rel="nofollow">ObjectDataSource</a><!--/noindex-->. Я выбрал ObjectDataSource, так как он зависит только от вашего кода и ему всё равно, откуда берутся данные - из базы данных, сервиса, файла, да чего угодно. <br/>
<br/>
Формализуем задачу. Необходимо реализовать такой же функционал, как и в предыдущем примере, но с использованием ObjectDataSource. Только на этот раз данные я буду хранить не на странице, а в статической переменной - чтобы эти данные были доступны в рамках всего приложения (ведь так и происходит, когда вы работаете, например, с базой данных). <br/>
<br/>
Вот класс автомобиля, с которым будем работать<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>public</span> <span>class</span> <span>Car</span></li>
 <li>{</li>
 <li> <span>public</span> <span>int</span> Id { <span>get</span>; <span>set</span>; }</li>
 <li> <span>public</span> <span>string</span> Manufacturer { <span>get</span>; <span>set</span>; }</li>
 <li> <span>public</span> <span>string</span> Model { <span>get</span>; <span>set</span>; }</li>
 <li>}</li>
 </ol></div></div><br/>
Начнем с класса-репозитория. Именно его методы будет вызывать ObjectDataSource для получения данных и манипуляции с ними. Хочу заметить, что я подобрал сигнатуру и набор методов репозитория специально для использования в ObjectDataSource. Вот сам класс:<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 3em; padding: 0 0 0 5px"><li><span>public</span> <span>class</span> <span>CarRepository</span></li>
 <li>{</li>
 <li> <span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li> <span>///</span><span> Статическая переменная. В ней будем хранить наши данные</span></li>
 <li> <span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li> <span>private</span> <span>static</span> <span>List</span>&lt;<span>Car</span>&gt; _store;</li>
 <li>&#160;</li>
 <li> <span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li> <span>///</span><span> Статический конструктор. Внутри инициализируем наши данные</span></li>
 <li> <span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li> <span>static</span> CarRepository()</li>
 <li> {</li>
 <li> _store = <span>new</span> <span>List</span>&lt;<span>Car</span>&gt;();</li>
 <li>&#160;</li>
 <li> <span>for</span> (<span>var</span> i = 0; i &lt; 1000; i++)</li>
 <li> {</li>
 <li> _store.Add(<span>new</span> <span>Car</span></li>
 <li> {</li>
 <li> Id = i,</li>
 <li> Manufacturer = <span>&quot;Manufacturer&quot;</span> + i,</li>
 <li> Model = <span>&quot;Model&quot;</span> + i</li>
 <li> });</li>
 <li> }</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li> <span>///</span><span> Получение данных. Принимает три параметра. Назначение первых двух очевидно, </span></li>
 <li> <span>///</span><span> а вот в третьем приходит информация для сортировки. Например, у нас сортировка по полю</span></li>
 <li> <span>///</span><span> &quot;Id&quot;. При сортировке по возрастанию переметр sort будет равен &quot;Id&quot;. </span></li>
 <li> <span>///</span><span> При сортировке по убыванию - &quot;Id DESC&quot;</span></li>
 <li> <span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li> <span>public</span> <span>IEnumerable</span>&lt;<span>Car</span>&gt; GetCars(<span>int</span> maximumRows, <span>int</span> startRowIndex, <span>string</span> sort)</li>
 <li> {</li>
 <li> <span>IEnumerable</span>&lt;<span>Car</span>&gt; temp = _store;</li>
 <li>&#160;</li>
 <li> <span>// Сперва определяем направление сортировки, затем поле, по которому сортируем</span></li>
 <li> <span>if</span> (sort.Contains(<span>&quot;DESC&quot;</span>))</li>
 <li> {</li>
 <li> <span>if</span> (sort.Contains(<span>&quot;Id&quot;</span>)) temp = _store.OrderByDescending(x =&gt; x.Id);</li>
 <li> <span>if</span> (sort.Contains(<span>&quot;Manufacturer&quot;</span>)) temp = _store.OrderByDescending(x =&gt; x.Manufacturer);</li>
 <li> <span>if</span> (sort.Contains(<span>&quot;Model&quot;</span>)) temp = _store.OrderByDescending(x =&gt; x.Model);</li>
 <li> }</li>
 <li> <span>else</span></li>
 <li> {</li>
 <li> <span>if</span> (sort.Contains(<span>&quot;Id&quot;</span>)) temp = _store.OrderBy(x =&gt; x.Id);</li>
 <li> <span>if</span> (sort.Contains(<span>&quot;Manufacturer&quot;</span>)) temp = _store.OrderBy(x =&gt; x.Manufacturer);</li>
 <li> <span>if</span> (sort.Contains(<span>&quot;Model&quot;</span>)) temp = _store.OrderBy(x =&gt; x.Model);</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>return</span> temp.Skip(startRowIndex).Take(maximumRows);</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li> <span>///</span><span> Необходим для подсчёта общего количества элеменов. </span></li>
 <li> <span>///</span><span> Используется для постраничного вывода данных</span></li>
 <li> <span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li> <span>public</span> <span>int</span> Count()</li>
 <li> {</li>
 <li> <span>return</span> _store.Count;</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li> <span>///</span><span> Для обновления в метод приходит экземпляр Car с</span></li>
 <li> <span>///</span><span> идентификатором обновляемой машины и новыми значениями полей</span></li>
 <li> <span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li> <span>public</span> <span>void</span> Update(<span>Car</span> car)</li>
 <li> {</li>
 <li> _store</li>
 <li> .Where(x =&gt; x.Id == car.Id)</li>
 <li> .ToList()</li>
 <li> .ForEach(x =&gt;</li>
 <li> {</li>
 <li> x.Manufacturer = car.Manufacturer;</li>
 <li> x.Model = car.Model;</li>
 <li> });</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li> <span>///</span><span> Удаление. Код и так понятен.</span></li>
 <li> <span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li> <span>public</span> <span>void</span> Delete(<span>Car</span> car)</li>
 <li> {</li>
 <li> _store = _store.Where(x =&gt; x.Id != car.Id).ToList();</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li> <span>///</span><span> Добавление</span></li>
 <li> <span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li> <span>public</span> <span>void</span> Insert(<span>Car</span> car)</li>
 <li> {</li>
 <li> car.Id = _store.Count &gt; 0 ? _store.Max(x =&gt; x.Id) + 1 : 1;</li>
 <li> _store.Add(car);</li>
 <li> }</li>
 <li>}</li>
 </ol></div></div><br/>
Отлично. Теперь, как и в предыдущем примере, добавляем страницу в проект и кидаем на эту страницу 2 текстбокса и кнопку (для возможности добавления)<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>&lt;</span><span>asp</span><span>:</span><span>TextBox</span> <span>runat</span><span>=&quot;server&quot;</span> <span>ID</span><span>=&quot;tbManufacturer&quot;&gt;</span></li>
 <li><span>&lt;/</span><span>asp</span><span>:</span><span>TextBox</span><span>&gt;</span></li>
 <li><span>&lt;</span><span>asp</span><span>:</span><span>TextBox</span> <span>runat</span><span>=&quot;server&quot;</span> <span>ID</span><span>=&quot;tbModel&quot;&gt;</span></li>
 <li><span>&lt;/</span><span>asp</span><span>:</span><span>TextBox</span><span>&gt;</span></li>
 <li><span>&lt;</span><span>asp</span><span>:</span><span>Button</span> <span>runat</span><span>=&quot;server&quot;</span> <span>OnClick</span><span>=&quot;BtAddCar&quot;</span> <span>Text</span><span>=&quot;+&quot;</span> <span>/&gt;</span></li>
 <li><span>&lt;</span><span>hr</span> <span>/&gt;</span></li>
 </ol></div></div><br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>protected</span> <span>void</span> BtAddCar(<span>object</span> sender, <span>EventArgs</span> e)</li>
 <li>{</li>
 <li> <span>if</span> (!<span>string</span>.IsNullOrEmpty(tbManufacturer.Text) &amp;&amp; !<span>string</span>.IsNullOrEmpty(tbModel.Text))</li>
 <li> {</li>
 <li> <span>var</span> carRepository = <span>new</span> <span>CarRepository</span>();</li>
 <li> carRepository.Insert(<span>new</span> <span>Car</span> {Manufacturer = tbManufacturer.Text, Model = tbModel.Text});</li>
 <li> gv.DataBind();</li>
 <li> }</li>
 <li>}</li>
 </ol></div></div><br/>
<div style="text-align: center"><!--noindex--><a href="http://4.bp.blogspot.com/-yDZCxla7VaY/TyGV4A1gniI/AAAAAAAAC-Q/eGuKDSIHZFY/s1600/6.PNG" rel="nofollow" style="margin-left: 1em; margin-right: 1em"><img src="http://4.bp.blogspot.com/-yDZCxla7VaY/TyGV4A1gniI/AAAAAAAAC-Q/eGuKDSIHZFY/s1600/6.PNG" border="0"/></a><!--/noindex--></div><br/>
Теперь поработаем над самим контролом ObjectDataSource.<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>&lt;</span><span>asp</span><span>:</span><span>ObjectDataSource</span> <span>ID</span><span>=&quot;ods&quot;</span> <span>runat</span><span>=&quot;server&quot;</span> <span>TypeName</span><span>=&quot;GridViewTest.CarRepository&quot;</span></li>
 <li> <span>DataObjectTypeName</span><span>=&quot;GridViewTest.Car&quot;</span> <span>EnablePaging</span><span>=&quot;True&quot;</span> <span>MaximumRowsParameterName</span><span>=&quot;maximumRows&quot;</span></li>
 <li> <span>StartRowIndexParameterName</span><span>=&quot;startRowIndex&quot;</span> <span>SortParameterName</span><span>=&quot;sort&quot;</span> <span>InsertMethod</span><span>=&quot;Insert&quot;</span></li>
 <li> <span>SelectCountMethod</span><span>=&quot;Count&quot;</span> <span>SelectMethod</span><span>=&quot;GetCars&quot;</span> <span>UpdateMethod</span><span>=&quot;Update&quot;</span> <span>DeleteMethod</span><span>=&quot;Delete&quot;&gt;</span></li>
 <li><span>&lt;/</span><span>asp</span><span>:</span><span>ObjectDataSource</span><span>&gt;</span></li>
 </ol></div></div><br/>
Поясню по каждому полю. <br/>
<ul><li><!--noindex--><a href="http://msdn.microsoft.com/ru-ru/library/system.web.ui.webcontrols.objectdatasource.typename.aspx" rel="nofollow">TypeName</a><!--/noindex-->=&quot;GridViewTest.CarRepository&quot; - указывает класс-источник данных</li>
 <li><!--noindex--><a href="http://feedproxy.google.com/~r/tym32167/~3/ga2Sni0amSk/msdn.microsoft.com/ru-ru/library/system.web.ui.webcontrols.objectdatasource.dataobjecttypename.aspx" rel="nofollow">DataObjectTypeName</a><!--/noindex-->=&quot;GridViewTest.Car&quot; - указывает тип объекта, которым будем оперировать. Благодаря этому мы можем в репозитории указывать методы, принимающие в качестве параметра экземпляр типа Car. Этот тип должен иметь конструктор без параметров и поля, доступные для записи.</li>
 <li><!--noindex--><a href="http://feedproxy.google.com/~r/tym32167/~3/ga2Sni0amSk/msdn.microsoft.com/ru-ru/library/system.web.ui.webcontrols.objectdatasource.enablepaging.aspx" rel="nofollow">EnablePaging</a><!--/noindex-->=&quot;True&quot; указываем, что используется постраничный вывод</li>
 <li><!--noindex--><a href="http://msdn.microsoft.com/ru-ru/library/system.web.ui.webcontrols.objectdatasource.maximumrowsparametername.aspx" rel="nofollow">MaximumRowsParameterName</a><!--/noindex-->=&quot;maximumRows&quot; <!--noindex--><a href="http://feedproxy.google.com/~r/tym32167/~3/ga2Sni0amSk/msdn.microsoft.com/ru-ru/library/system.web.ui.webcontrols.objectdatasource.startrowindexparametername.aspx" rel="nofollow">StartRowIndexParameterName</a><!--/noindex-->=&quot;startRowIndex&quot; <!--noindex--><a href="http://feedproxy.google.com/~r/tym32167/~3/ga2Sni0amSk/msdn.microsoft.com/ru-ru/library/system.web.ui.webcontrols.objectdatasource.sortparametername.aspx" rel="nofollow">SortParameterName</a><!--/noindex-->=&quot;sort&quot; имена параметров в методах</li>
 <li><!--noindex--><a href="http://msdn.microsoft.com/ru-ru/library/system.web.ui.webcontrols.objectdatasource.insertmethod.aspx" rel="nofollow">InsertMethod</a><!--/noindex-->=&quot;Insert&quot; <!--noindex--><a href="http://msdn.microsoft.com/ru-ru/library/system.web.ui.webcontrols.objectdatasource.selectcountmethod.aspx" rel="nofollow">SelectCountMethod</a><!--/noindex-->=&quot;Count&quot; <!--noindex--><a href="http://feedproxy.google.com/~r/tym32167/~3/ga2Sni0amSk/msdn.microsoft.com/ru-ru/library/system.web.ui.webcontrols.objectdatasource.selectmethod.aspx" rel="nofollow">SelectMethod</a><!--/noindex-->=&quot;GetCars&quot; <!--noindex--><a href="http://feedproxy.google.com/~r/tym32167/~3/ga2Sni0amSk/msdn.microsoft.com/ru-ru/library/system.web.ui.webcontrols.objectdatasource.updatemethod.aspx" rel="nofollow">UpdateMethod</a><!--/noindex-->=&quot;Update&quot; <!--noindex--><a href="http://msdn.microsoft.com/ru-ru/library/system.web.ui.webcontrols.objectdatasource.deletemethod.aspx" rel="nofollow">DeleteMethod</a><!--/noindex-->=&quot;Delete&quot; имена методов в репозитории</li>
 </ul><br/>
Теперь у нас всё готово для того, чтобы добавить на страницу грид. Приведу весь его код.<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>&lt;</span><span>asp</span><span>:</span><span>GridView</span> <span>runat</span><span>=&quot;server&quot;</span> <span>ID</span><span>=&quot;gv&quot;</span> <span>AllowSorting</span><span>=&quot;True&quot;</span> <span>DataKeyNames</span><span>=&quot;Id&quot;</span> <span>AutoGenerateColumns</span><span>=&quot;False&quot;</span></li>
 <li> <span>DataSourceID</span><span>=&quot;ods&quot;</span> <span>Width</span><span>=&quot;60%&quot;</span> <span>AllowPaging</span><span>=&quot;True&quot;</span> <span>PageSize</span><span>=&quot;20&quot;&gt;</span></li>
 <li> <span>&lt;</span><span>Columns</span><span>&gt;</span></li>
 <li> <span>&lt;%</span><span>--Тут, как и в предыдущем примере, я использую BoundField--</span><span>%&gt;</span></li>
 <li> <span>&lt;</span><span>asp</span><span>:</span><span>BoundField</span> <span>HeaderText</span><span>=&quot;ИД&quot;</span> <span>DataField</span><span>=&quot;Id&quot;</span> <span>ReadOnly</span><span>=&quot;True&quot;</span> <span>SortExpression</span><span>=&quot;Id&quot;&gt;</span></li>
 <li> <span>&lt;</span><span>ItemStyle</span> <span>Width</span><span>=&quot;5%&quot;&gt;&lt;/</span><span>ItemStyle</span><span>&gt;</span></li>
 <li> <span>&lt;/</span><span>asp</span><span>:</span><span>BoundField</span><span>&gt;</span></li>
 <li> <span>&lt;%</span><span>--Здесь я тоже мог бы использовать BoundField, но я хотел показать, как использовать</span></li>
 <li> <span>TemplateField с односторонней (Eval) и двухсторонней (Bind) привязкой данных--</span><span>%&gt;</span></li>
 <li> <span>&lt;</span><span>asp</span><span>:</span><span>TemplateField</span> <span>HeaderText</span><span>=&quot;Производитель&quot;</span> <span>SortExpression</span><span>=&quot;Manufacturer&quot;&gt;</span></li>
 <li> <span>&lt;</span><span>ItemStyle</span> <span>Width</span><span>=&quot;35%&quot;&gt;&lt;/</span><span>ItemStyle</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>ItemTemplate</span><span>&gt;</span></li>
 <li> <span>&lt;%</span><span>#</span>Eval(<span>&quot;Manufacturer&quot;</span>)<span>%&gt;</span></li>
 <li> <span>&lt;/</span><span>ItemTemplate</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>EditItemTemplate</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>asp</span><span>:</span><span>TextBox</span> <span>runat</span><span>=&quot;server&quot;</span> <span>ID</span><span>=&quot;tbMan&quot;</span> <span>Text</span><span>='</span><span>&lt;%</span><span>#</span>Bind(&quot;Manufacturer&quot;) <span>%&gt;</span><span>'&gt;&lt;/</span><span>asp</span><span>:</span><span>TextBox</span><span>&gt;</span></li>
 <li> <span>&lt;/</span><span>EditItemTemplate</span><span>&gt;</span></li>
 <li> <span>&lt;/</span><span>asp</span><span>:</span><span>TemplateField</span><span>&gt;</span></li>
 <li> <span>&lt;%</span><span>--Тут всё аналогично предыдущему столбцу--</span><span>%&gt;</span></li>
 <li> <span>&lt;</span><span>asp</span><span>:</span><span>TemplateField</span> <span>HeaderText</span><span>=&quot;Модель&quot;</span> <span>SortExpression</span><span>=&quot;Model&quot;&gt;</span></li>
 <li> <span>&lt;</span><span>ItemStyle</span> <span>Width</span><span>=&quot;35%&quot;&gt;&lt;/</span><span>ItemStyle</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>ItemTemplate</span><span>&gt;</span></li>
 <li> <span>&lt;%</span><span>#</span>Eval(<span>&quot;Model&quot;</span>)<span>%&gt;</span></li>
 <li> <span>&lt;/</span><span>ItemTemplate</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>EditItemTemplate</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>asp</span><span>:</span><span>TextBox</span> <span>runat</span><span>=&quot;server&quot;</span> <span>ID</span><span>=&quot;tbModel&quot;</span> <span>Text</span><span>='</span><span>&lt;%</span><span>#</span>Bind(&quot;Model&quot;) <span>%&gt;</span><span>'&gt;&lt;/</span><span>asp</span><span>:</span><span>TextBox</span><span>&gt;</span></li>
 <li> <span>&lt;/</span><span>EditItemTemplate</span><span>&gt;</span></li>
 <li> <span>&lt;/</span><span>asp</span><span>:</span><span>TemplateField</span><span>&gt;</span></li>
 <li> <span>&lt;%</span><span>--Я хочу показать, что для того, чтобы использовать кнопки редактирования/удаления,</span></li>
 <li> <span>вам не обязательно пользоваться CommandField. Достаточно указать нужное значение в поле</span></li>
 <li> <span>CommandName любого кнопочного контрола--</span><span>%&gt;</span></li>
 <li> <span>&lt;</span><span>asp</span><span>:</span><span>TemplateField</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>ItemStyle</span> <span>Width</span><span>=&quot;25%&quot;&gt;&lt;/</span><span>ItemStyle</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>ItemTemplate</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>asp</span><span>:</span><span>LinkButton</span> <span>runat</span><span>=&quot;server&quot;</span> <span>CommandName</span><span>=&quot;Edit&quot;</span> <span>Text</span><span>=&quot;Изменить&quot;&gt;&lt;/</span><span>asp</span><span>:</span><span>LinkButton</span><span>&gt;</span></li>
 <li> <span>&lt;%</span><span>--А раз это простые кнопки, то можно им добавлять нужное поведение. Например, </span></li>
 <li> <span>OnClientClick отработает на клиенте, спросит у пользователя разрешение на действие,</span></li>
 <li> <span>и постбек произойдет только в том случае, если пользователь ответит утвердительно --</span><span>%&gt;</span></li>
 <li> <span>&lt;</span><span>asp</span><span>:</span><span>LinkButton</span> <span>runat</span><span>=&quot;server&quot;</span> <span>CommandName</span><span>=&quot;Delete&quot;</span> <span>Text</span><span>=&quot;Удалить&quot;</span> </li>
 <li> <span>OnClientClick</span><span>=&quot;return confirm('Вы действительно хотите удалить запись?');&quot;&gt;&lt;/</span><span>asp</span><span>:</span><span>LinkButton</span><span>&gt;</span></li>
 <li> <span>&lt;/</span><span>ItemTemplate</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>EditItemTemplate</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>asp</span><span>:</span><span>LinkButton</span> <span>runat</span><span>=&quot;server&quot;</span> <span>CommandName</span><span>=&quot;Update&quot;</span> <span>Text</span><span>=&quot;Обновить&quot;&gt;&lt;/</span><span>asp</span><span>:</span><span>LinkButton</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>asp</span><span>:</span><span>LinkButton</span> <span>runat</span><span>=&quot;server&quot;</span> <span>CommandName</span><span>=&quot;Cancel&quot;</span> <span>Text</span><span>=&quot;Отменить&quot;&gt;&lt;/</span><span>asp</span><span>:</span><span>LinkButton</span><span>&gt;</span></li>
 <li> <span>&lt;/</span><span>EditItemTemplate</span><span>&gt;</span></li>
 <li> <span>&lt;/</span><span>asp</span><span>:</span><span>TemplateField</span><span>&gt;</span></li>
 <li> <span>&lt;/</span><span>Columns</span><span>&gt;</span></li>
 <li> <span>&lt;%</span><span>--Контент, который будет показан, если записей не будет вовсе--</span><span>%&gt;</span></li>
 <li> <span>&lt;</span><span>EmptyDataTemplate</span><span>&gt;</span></li>
 <li> Записей нет<span>&lt;/</span><span>EmptyDataTemplate</span><span>&gt;</span></li>
 <li><span>&lt;/</span><span>asp</span><span>:</span><span>GridView</span><span>&gt;</span></li>
 </ol></div></div><br/>
Собрав всё вместе, получаем результат:<br/>
<br/>
<div style="text-align: center"><!--noindex--><a href="http://3.bp.blogspot.com/-ECdrR2rpIsY/TyGhVS2iqeI/AAAAAAAAC-c/tr91tacDq7I/s1600/7.PNG" rel="nofollow" style="margin-left: 1em; margin-right: 1em"><img src="http://3.bp.blogspot.com/-ECdrR2rpIsY/TyGhVS2iqeI/AAAAAAAAC-c/tr91tacDq7I/s1600/7.PNG" border="0"/></a><!--/noindex--></div><br/>
<div style="text-align: center"><!--noindex--><a href="http://1.bp.blogspot.com/-K-jRNuDyU-4/TyGheFWFDtI/AAAAAAAAC-o/t5FZ7JyIZnk/s1600/8.PNG" rel="nofollow" style="margin-left: 1em; margin-right: 1em"><img src="http://1.bp.blogspot.com/-K-jRNuDyU-4/TyGheFWFDtI/AAAAAAAAC-o/t5FZ7JyIZnk/s1600/8.PNG" border="0"/></a><!--/noindex--></div><br/>
Вот и всё. Данные можно изменять, сортировать, удалять. <br/>
<br/>
Таким образом, используя GridView и различные источники данных, можно легко манипулировать данными и представлять их в удобном для вас виде. <br/>
<br/>
<!--noindex--><a href="http://narod.ru/disk/38868897001/GridViewTest.zip.html" rel="nofollow">Исходный код солюшена</a><!--/noindex--><br/>
<br/>
Полезные ссылки:<br/>
<ul><li><!--noindex--><a href="http://habrahabr.ru/blogs/net/44885/" rel="nofollow">GridView, и с чем его едят</a><!--/noindex--></li>
 <li><!--noindex--><a href="http://habrahabr.ru/blogs/net/44982/" rel="nofollow">GridView, и с чем его едят (часть вторая, большая)</a><!--/noindex--></li>
 <li><!--noindex--><a href="http://www.asp.net/web-forms/tutorials/data-access/basic-reporting/displaying-data-with-the-objectdatasource-cs" rel="nofollow">Displaying Data With the ObjectDataSource (C#)</a><!--/noindex--></li>
 <li><!--noindex--><a href="http://www.codeproject.com/Articles/13524/ObjectDataSource-In-Depth" rel="nofollow">ObjectDataSource In Depth</a><!--/noindex--></li>
 </ul><br/>
</div><br/>
<div><img src="https://blogger.googleusercontent.com/tracker/8897990838383834685-518143324899101997?l=tym32167.blogspot.com" width="1px" height="1px" border="0"/></div>]]></description>
      <category><![CDATA[.NET]]></category>
      <category><![CDATA[ASP.NET]]></category>
      <category><![CDATA[C#]]></category>
      <guid>http://feedproxy.google.com/~r/tym32167/~3/ga2Sni0amSk/aspnet-gridview.html</guid>
      <pubDate>Thu, 26 Jan 2012 19:38:00 UT</pubDate>
      <dc:creator><![CDATA[tym32167]]></dc:creator>
    </item>
    <item>
      <title><![CDATA[DevCon'12: ключевыми докладчиками конференции станут Скотт Хансельман и Йонас Перссон]]></title>
      <link>http://microgeek.ru/blogs/conf/1728/</link>
      <description><![CDATA[<p>Ключевыми докладчиками второй ежегодной конференции по разработке программного обеспечения <!--noindex--><a href="http://www.msdevcon.ru/" rel="nofollow">DevCon’12</a><!--/noindex--> станут <!--noindex--><a href="http://www.msdevcon.ru/speakers" rel="nofollow">Йонас Персcон</a><!--/noindex-->, главный операционный директор (Chief Operating Officer) департамента стратегических технологий корпорации Microsoft, и <!--noindex--><a href="http://www.msdevcon.ru/speakers" rel="nofollow">Скотт Хансельман</a><!--/noindex-->, главный архитектор по проектам с сообществами (Principal Community Architect) корпорации Microsoft. В рамках конференции они представят два пленарных доклада, в которых будет подробно рассказано о развитии ключевых технологий Microsoft. Традиционно выступление докладчиков будет сопровождаться демонстрацией новейших возможностей платформы Microsoft. Конференция <!--noindex--><a href="http://www.msdevcon.ru/" rel="nofollow">DevCon’12</a><!--/noindex--> пройдет 23-24 мая 2012 года в Подмосковье, в природном курорте &#171;Яхонты&#187;. </p> <p>&#171;В этом году мы расширили программу конференции: впервые будет представлено два пленарных доклада – в первый и второй день проведения мероприятия. Такой подход позволит всем участникам DevCon’12 получить детальную информацию о важнейших трендах индустрии и новых решениях и технологиях Microsoft, которые помогут экспертам в области разработки быть по-настоящему успешными. Кроме того, все участники конференции смогут напрямую пообщаться с Йонасом Перссоном и Скоттом Хансельманом, которые обладают большим авторитетом в индустрии, и получить буквально из первых рук актуальную информацию о том, что будет определять развитие ИТ в ближайшее время&#187;, – сказал Александр Ложечкин, директор департамента стратегических технологий Microsoft в России. </p> <p><img src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-44-06-metablogapi/8880.clip_5F00_image002_5F00_74A57A64.jpg" alt="clip_image002" title="clip_image002" width="102px" height="136px" hspace="12" border="0"/></p> <p>В первый день работы конференции перед ее участниками выступит Йонас Персcон, главный операционный директор департамента стратегических технологий корпорации Microsoft. Йонас отвечает за ключевые инициативы компании, которые направлены на стимулирование локальных рынков информационных технологий как в развитых, так и в развивающихся странах. Обладая большим опытом работы не только в ИТ, но также телекоммуникационной, финансовой и венчурной индустриях, он часто консультирует научные и коммерческие организации и государственные структуры по вопросам развития бизнеса и локальной экономики. Доклад Йонаса будет посвящен обзору платформы Microsoft и тем возможностям, которые она предлагает как индивидуальным разработчикам, так и организациям любого размера, создающим программные продукты.</p> <p><img src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-44-06-metablogapi/0844.clip_5F00_image004_5F00_61844DB8.jpg" alt="clip_image004" title="clip_image004" width="104px" height="137px" hspace="12" border="0"/></p> <p>Программа второго дня конференции откроется выступлением Скотта Хансельмана, главного архитектора по проектам с сообществами корпорации Microsoft, и одного из самых известных и уважаемых в мире специалистов по веб-технологиям Microsoft. Он подробно расскажет о современном инструментарии, созданном базе ASP.NET. Не останется в стороне и тема современных облачных технологий Windows Azure, которые выводят возможности веб-разработки на принципиально новый уровень.</p> <p>Подробная информация о ключевых докладчиках второй ежегодной конференции по разработке программного обеспечения DevCon’12 доступна по адресу: <!--noindex--><a href="http://www.msdevcon.ru/speakers" rel="nofollow">http://www.msdevcon.ru/speakers</a><!--/noindex-->. </p> <p>Спешите <!--noindex--><a href="https://www.msdevcon.ru/register" rel="nofollow">зарегистрироваться на сайте конференции</a><!--/noindex-->: до 13 февраля действуют максимальные скидки на участие в DevCon’12.</p> <p>Получить дополнительную информацию о конференции и зарегистрироваться можно по адресу: <!--noindex--><a href="http://www.msdevcon.ru/" rel="nofollow">http://www.msdevcon.ru/</a><!--/noindex-->. Следите за новостями конференции в Твиттер: подпишитесь на официальный Твиттер конференции <!--noindex--><a href="http://twitter.com/msdevcon" rel="nofollow">@msdevcon</a><!--/noindex--> и общайтесь, используя хеш-тег #msdevcon.</p> <p><b>Информация о </b><b>DevCon</b></p> <p>DevCon – это серия ежегодных масштабных конференций Microsoft, посвященных разработке программного обеспечения. В конференции принимают участие ведущие эксперты индустрии и разработчики продуктовых команд из Редмонда. Двухдневная программа DevCon’12 включает пленарную сессию, 50 технических докладов, мастер-классы, круглые столы, зону &#171;Спроси эксперта&#187;, партнерскую выставку и различные интерактивные мероприятия. <!--noindex--><a href="http://www.msdevcon.ru/topics" rel="nofollow">Основными темами</a><!--/noindex--> конференции&#160; станут:</p> <ul> <li>Клиентская разработка; </li>
 <li>Мобильная разработка; </li>
 <li>Веб-разработка; </li>
 <li>Облачные вычисления; </li>
 <li>Средства разработки и управление жизненным циклом програмного обеспечения; </li>
 <li>Технологии разработки и языки программирования; </li>
 <li>Корпоративная разработка; </li>
 <li>Взаимодействие с другими платформами и технологиями. </li>
 </ul> <p>Конференция DevCon’11, прошедшая в мае 2011 г., за 2 дня своей работы собрала более 650 профессионалов в области разработки ПО, а количество онлайн-слушателей докладов о настоящем и будущем разработки и платформы Microsoft составило около 30 тысяч человек. С материалами конференции DevCon’11 можно ознакомиться по адресу: <!--noindex--><a href="http://www.msdevcon.ru/devcon11/" rel="nofollow">http://www.msdevcon.ru/devcon11/</a><!--/noindex--></p> ]]></description>
      <category><![CDATA[microsoft]]></category>
      <category><![CDATA[devcon]]></category>
      <guid isPermaLink="false">urn:bitrix:blog:post:1728</guid>
      <pubDate>Thu, 26 Jan 2012 06:12:19 UT</pubDate>
      <dc:creator><![CDATA[Vladimir Yunev]]></dc:creator>
    </item>
    <item>
      <title><![CDATA[SharePoint для интернет-сайтов. Введение]]></title>
      <link>http://microgeek.ru/blogs/dplotnikov/1727/</link>
      <description><![CDATA[<p>Многие компании используют SharePoint 2010 в качестве платформы для построения корпоративных порталов для внутреннего использования. Но немногие знают, что SharePoint также можно использовать для создания публичных веб-сайтов. Особенно полезна данная возможность для тех компаний, которые уже используют SharePoint, позволяющая снизить затраты на обучение персонала. </p> <ul><li>Введение</li>
 <li>Интранет и интернет – различия и сходства </li>
 <li>Лицензирование </li>
 </ul> <h4>Введение</h4> <p>На сайте <!--noindex--><a href="http://www.wssdemo.com/livepivot/" rel="nofollow">Top SharePoint internet Sites</a><!--/noindex--> можно посмотреть некоторые примеры сайтов, реализованные с помощью SharePoint для интернет-сайтов. При этом обратите внимание на внешний вид сайтов, по которому иногда сложно догадаться, что он сделан с использованием SharePoint. В этом плане очень удачным получился сайт <!--noindex--><a href="http://www.ferrari.com/" rel="nofollow">Ferrari</a><!--/noindex--> (рис. 1). </p> <p><img src="http://dplotnikov.files.wordpress.com/2012/01/image.png" border="0"/> </p> <p>Рис. 1. Пример веб-сайта, сделанного с помощью SharePoint </p> <p>Работать с веб-сайтом можно при помощи SharePoint Designer 2010 или делать все через браузер, используя все возможности платформы в управлении веб-контентом. </p> <p>Преждем чем начать работу, рассмотрим некоторые особенности SharePoint для интернет-сайтов, позволяющие лучше понять, как использовать возможности платформы по максимуму. </p> <h4>Интранет и интернет – различия и сходства</h4> <p>Для начала нужно понять различия сайта на основе шаблона публикации (рис. 2) в случае его работы в интранете и интернете. </p> <ul><li>Посетители публичного сайта – анонимные пользователи. Кроме этого, на сайте могут быть авторы, утвердители контента и разработчики </li>
 <li>Для веб-сайтов часто используются варианты, когда контент доступен на разных языках в зависимости от выбора пользователя. При этом возможность многоязычного интерфейса может быть не нужна, т.к. анонимные пользователи видят только содержимое на страницах публикации </li>
 <li>На веб-сайтах из всего многообразия служб SharePoint чаще всего используются только поиск и служба метаданных для классификации содержимого и указания ключевых слов </li>
 </ul> <p><img src="http://dplotnikov.files.wordpress.com/2012/01/image1.png" border="0"/></p> <p>Рис. 2. Внешний вид сайта, созданного из шаблона публикации </p> <p>Вместе с тем, нужно понимать общие черты сайтов, создаваемых для интранет и экстранет </p> <ul><li>Занимайтесь планированием, при этом можете начать работу с создания сайта для интранета </li>
 <li>Продумайте дизайн вашего сайта </li>
 <li>Продумайте использование возможности по публикации контента </li>
 <li>Создайте удобную и понятную для пользователей навигацию </li>
 <li>Используйте службу метаданных для улучшения результатов поиска </li>
 </ul> <h4>Лицензирование </h4> <p>Самый тонкий момент при работе с публичными интернет сайтами – лицензирование. </p> <p>При использовании SharePoint Server 2010 нужна серверная лицензия на SharePoint и отдельная лицензия SharePoint Server 2010 для интернет-сайтов. При этом не нужно покупать клиентские лицензии. Тут стоит различать стандартную серверную лицензию для интернет-сайтов, предназначенную для небольших и средних компаний и поддерживает только один домен и поддомены. И также есть лицензия Enterprise, включающая эти же возможности, а также поддержка нескольких доменов и право использования Microsoft FAST Search для веб-сайтов. Подробную информацию по лицензированию можно посмотреть <!--noindex--><a href="http://sharepoint.microsoft.com/ru-ru/buy/Pages/Licensing-Details.aspx" rel="nofollow">здесь</a><!--/noindex-->. </p> <p>С появлением Office 365 можно создавать публичные веб-сайты с помощью SharePoint Online. При этом в подписку уже входит возможность создания одного публичного веб-сайта (создается как отдельная коллекция сайтов). </p> <p>Таким образом, обдумав описанное выше, можно начинать создание публичного веб-сайта, чем мы и займемся в следующих статьях.</p>]]></description>
      <category><![CDATA[sharepoint 2010]]></category>
      <category><![CDATA[sharepoint for internet sites]]></category>
      <category><![CDATA[sharepoint для интернет сайтов]]></category>
      <guid isPermaLink="false">urn:bitrix:blog:post:1727</guid>
      <pubDate>Tue, 24 Jan 2012 06:10:39 UT</pubDate>
      <dc:creator><![CDATA[Dmitry Plotnikov]]></dc:creator>
    </item>
    <item>
      <title><![CDATA[Бесплатный вебинар про новшества в ASP.NET и новой Visual Studio 11 для веб-разработчиков]]></title>
      <link>http://microgeek.ru/blogs/conf/1726/</link>
      <description><![CDATA[<p><img src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-44-06-metablogapi/5126.image_5F00_662C9C7C.png" alt="image" title="image" width="461px" height="329px" border="0"/></p> <p>Уважаемые коллеги, веб-разработчики и просто интересующиеся! Приглашаю вас посетить <!--noindex--><a href="https://msevents.microsoft.com/cui/EventDetail.aspx?EventID=1032503722&amp;culture=ru-RU" rel="nofollow">бесплатный вебинар</a><!--/noindex--> (онлайн мероприятие), на котором я расскажу слушателям про новые возможности платформы ASP.NET и среды разработки Visual Studio следующего поколения, предназначенные для веб-разработчиков, для удобной и эффективной работы с веб-проектами.</p> <p>В рамках 45 минут вебинара я познакомлю вас с нововведениями в среде разработки и новшествами во фреймворках, призванными повысить эффективность программиста, Вашему вниманию будет представлен новый удобный инструмент Page Inspector, интегрирующийся в Visual Studio 11. Я расскажу про нововведения в ASP.NET WebForms последней версии, направленные на упрощение разработки и значительное повышение эффективности использования фреймворка. Мы рассмотрим новые возможности ASP.NET MVC 4 и механизм рецептов, который был представлен вместе с MVC 4 и доступный в&#160; Visual Studio.</p> <p>Вебинар пройдет <strong>26 января в 17-00</strong> московского времени и будет доступен всем желающим. Сессия займет от 45 минут до часа, после чего я буду рад ответить на любые ваши вопросы. Вебинар будет записываться, запись станет доступна для свободного просмотра через несколько дней после проведения мероприятия.</p> <p>Я прошу всех желающих зарегистрироваться на вебинар по следующему адресу на <!--noindex--><a href="https://msevents.microsoft.com/cui/EventDetail.aspx?EventID=1032503722&amp;culture=ru-RU" rel="nofollow">странице мероприятий Microsoft</a><!--/noindex-->. </p> <p>Регистрация не обязательна, но желательна, она позволит вам получить напоминание о мероприятии. Если нет желания регистрироваться, то приходите на вебинар по <!--noindex--><a href="https://msevents.microsoft.com/cui/r.aspx?t=0&amp;c=ru-ru&amp;e=1032504160&amp;p=fPYfQkFrE5E=TVBSb2WNIWf3y2gZACOLaQ==" rel="nofollow">следующей ссылке на прямую трансляцию</a><!--/noindex-->.</p> <p>До встречи на вебинаре!</p>]]></description>
      <category><![CDATA[asp.net]]></category>
      <category><![CDATA[asp.net mvc]]></category>
      <category><![CDATA[visual studio]]></category>
      <category><![CDATA[веб-разработка]]></category>
      <category><![CDATA[вебинары]]></category>
      <guid isPermaLink="false">urn:bitrix:blog:post:1726</guid>
      <pubDate>Thu, 19 Jan 2012 18:49:48 UT</pubDate>
      <dc:creator><![CDATA[Vladimir Yunev]]></dc:creator>
    </item>
    <item>
      <title><![CDATA[Программируем списки переходов или как сократить количество ярлыков на рабочем столе]]></title>
      <link>http://microgeek.ru/blogs/tym32167/1721/</link>
      <description><![CDATA[<div style="text-align: left">Здравствуйте. Я думаю, у каждого программиста есть свой набор примочек, программ, которые делают процесс работы проще и приятней. Сегодня речь пойдет об одной из таких программ, а точнее о том, как использовать списки переходов (jump lists), дабы уменьшить количество ярлыков на рабочем столе. Вот, что мы получим в итоге:<br/>
<div style="text-align: center"><!--noindex--><a href="http://1.bp.blogspot.com/-1Ac1i0dYQQ4/TxAumisMMaI/AAAAAAAAC8E/1_kpiSNajuY/s1600/1.png" rel="nofollow" style="margin-left: 1em; margin-right: 1em"><img src="http://1.bp.blogspot.com/-1Ac1i0dYQQ4/TxAumisMMaI/AAAAAAAAC8E/1_kpiSNajuY/s400/1.png" width="210px" height="400px" border="0"/></a><!--/noindex--></div>За подробностями прошу под кат.<br/>
<a name="more" rel="nofollow"></a><br/>
<br/>
Итак, начальные условия:<br/>
1. У меня есть около 15 программ, которыми я пользуюсь часто (хотя бы раз в день). Хочу иметь возможность запускать эти программы быстро и удобно<br/>
2. Большая часть этих программ лежит в папке, которая синхронизируется между всеми моими компами/виртуалками<br/>
3. Общее между всеми компами то, что там везде установлена Windows 7<br/>
<br/>
Задача:<br/>
Написать программу, которая также будет синхронизирована между всеми компами и хранить информацию о запускаемых приложениях, давая возможность запускать эти приложения.<br/>
<br/>
Как я это вижу:<br/>
<br/>
Для каждой программы надо будет сделать описание (путь к exe файлу, название программы, описание и категория - это как минимум). Набор этих описаний я буду хранить в файле в той же папке что и саму программу. Тогда, благодаря синхронизации, у меня будет один общий список запускаемых программ для всех компьютеров. В самой программе нужно реализовать механизм заполнения списков переходов, запуска приложения из программы, ну и возможность редактирования названия и описания приложения. <br/>
<br/>
Инструменты:<br/>
1. <!--noindex--><a href="http://windows.microsoft.com/ru-RU/windows7/products/features/jump-lists" rel="nofollow">Списки переходов</a><!--/noindex--><br/>
2. Я выбрал WPF, так как это моя слабая сторона. Повышаю опыт.<br/>
3. <!--noindex--><a href="http://mvvmlight.codeplex.com/" rel="nofollow">MVVM Light Toolkit</a><!--/noindex--><br/>
<br/>
Ну, вроде всё. Поехали!<br/>
<br/>
Для начала я набросал класс этого описания программы<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>namespace</span> TaskStart.Tasks</li>
 <li>{</li>
 <li> [<span>Serializable</span>]</li>
 <li> <span>public</span> <span>class</span> <span>Task</span></li>
 <li> {</li>
 <li> [<span>XmlAttribute</span>]</li>
 <li> <span>public</span> <span>string</span> ApplicationPath { <span>get</span>; <span>set</span>; }</li>
 <li>&#160;</li>
 <li> [<span>XmlAttribute</span>]</li>
 <li> <span>public</span> <span>string</span> Title { <span>get</span>; <span>set</span>; }</li>
 <li>&#160;</li>
 <li> [<span>XmlAttribute</span>]</li>
 <li> <span>public</span> <span>string</span> Description { <span>get</span>; <span>set</span>; }</li>
 <li>&#160;</li>
 <li> [<span>XmlAttribute</span>]</li>
 <li> <span>public</span> <span>string</span> Category { <span>get</span>; <span>set</span>; }</li>
 <li> }</li>
 <li>}</li>
 </ol></div></div><br/>
Тут ничего сложного. Далее, мне надо было определить механизм сохранения/загрузки. Я сделал простой класс Settings. Синглтоном я его сделал ради забавы, мог бы реализовать и по другому, но мне так больше нравится. Комментариев я не писал, так как код ну очень простой.<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>public</span> <span>class</span> <span>Settings</span></li>
 <li>{</li>
 <li> <span>private</span> <span>const</span> <span>string</span> SettingsFileName = <span>&quot;Settings.xml&quot;</span>;</li>
 <li>&#160;</li>
 <li> <span>private</span> Settings()</li>
 <li> {</li>
 <li>&#160;</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>private</span> <span>static</span> <span>Settings</span> _instance;</li>
 <li> <span>public</span> <span>static</span> <span>Settings</span> Instance</li>
 <li> {</li>
 <li> <span>get</span> { <span>return</span> _instance ?? (_instance = <span>new</span> <span>Settings</span>()); }</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>public</span> <span>IEnumerable</span>&lt;<span>Task</span>&gt; GetTasks()</li>
 <li> {</li>
 <li> <span>var</span> result = <span>new</span> <span>List</span>&lt;<span>Task</span>&gt;();</li>
 <li> <span>if</span> (<span>File</span>.Exists(SettingsFileName))</li>
 <li> {</li>
 <li> <span>try</span></li>
 <li> {</li>
 <li> <span>var</span> xmlSer = <span>new</span> <span>XmlSerializer</span>(<span>typeof</span>(<span>List</span>&lt;<span>Task</span>&gt;));</li>
 <li> <span>using</span> (<span>var</span> sr = <span>new</span> <span>StreamReader</span>(SettingsFileName))</li>
 <li> {</li>
 <li> <span>var</span> res = xmlSer.Deserialize(sr) <span>as</span> <span>List</span>&lt;<span>Task</span>&gt;;</li>
 <li> result = res ?? <span>new</span> <span>List</span>&lt;<span>Task</span>&gt;();</li>
 <li> }</li>
 <li> }</li>
 <li> <span>catch</span> (<span>Exception</span>)</li>
 <li> {</li>
 <li> <span>return</span> result;</li>
 <li> }</li>
 <li> }</li>
 <li> <span>return</span> result;</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>public</span> <span>void</span> SetTasks(<span>IEnumerable</span>&lt;<span>Task</span>&gt; tasks)</li>
 <li> {</li>
 <li> <span>var</span> taskList = tasks.ToList();</li>
 <li> <span>using</span> (<span>var</span> sw = <span>new</span> <span>StreamWriter</span>(SettingsFileName, <span>false</span>))</li>
 <li> {</li>
 <li> <span>var</span> xmlSer = <span>new</span> <span>XmlSerializer</span>(<span>typeof</span>(<span>List</span>&lt;<span>Task</span>&gt;));</li>
 <li> xmlSer.Serialize(sw, taskList);</li>
 <li> }</li>
 <li> }</li>
 <li>}</li>
 </ol></div></div><br/>
Вот пример полученного на выходе XML<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>&lt;?</span><span>xml</span><span> </span><span>version</span><span>=</span>&quot;<span>1.0</span>&quot;<span> </span><span>encoding</span><span>=</span>&quot;<span>utf-8</span>&quot;<span>?&gt;</span></li>
 <li><span>&lt;</span><span>ArrayOfTask</span><span> </span><span>xmlns:xsi</span><span>=</span>&quot;<span>http://www.w3.org/2001/XMLSchema-instance</span>&quot;<span> </span><span>xmlns:xsd</span><span>=</span>&quot;<span>http://www.w3.org/2001/XMLSchema</span>&quot;<span>&gt;</span></li>
 <li> <span>&lt;</span><span>Task</span><span> </span><span>ApplicationPath</span><span>=</span>&quot;<span>D:\Pub\Tools\foobar2000\foobar2000.exe</span>&quot;<span> </span><span>Title</span><span>=</span>&quot;<span>foobar2000</span>&quot;<span> </span><span>Category</span><span>=</span>&quot;<span>Entertainment</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Task</span><span> </span><span>ApplicationPath</span><span>=</span>&quot;<span>D:\Pub\Tools\The KMPlayer\KMPlayer.exe</span>&quot;<span> </span><span>Title</span><span>=</span>&quot;<span>KMPlayer</span>&quot;<span> </span><span>Category</span><span>=</span>&quot;<span>Entertainment</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Task</span><span> </span><span>ApplicationPath</span><span>=</span>&quot;<span>D:\Pub\Miranda IM\MirandaPortable.exe</span>&quot;<span> </span><span>Title</span><span>=</span>&quot;<span>Miranda</span>&quot;<span> </span><span>Category</span><span>=</span>&quot;<span>Messaging</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Task</span><span> </span><span>ApplicationPath</span><span>=</span>&quot;<span>C:\Program Files (x86)\Skype\Phone\Skype.exe</span>&quot;<span> </span><span>Title</span><span>=</span>&quot;<span>Skype</span>&quot;<span> </span><span>Category</span><span>=</span>&quot;<span>Messaging</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Task</span><span> </span><span>ApplicationPath</span><span>=</span>&quot;<span>D:\Pub\Tools\DotNetNotepad\DotNetNotepad.UI.exe</span>&quot;<span> </span><span>Title</span><span>=</span>&quot;<span>DotNetNotepad</span>&quot;<span> </span><span>Category</span><span>=</span>&quot;<span>Office</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Task</span><span> </span><span>ApplicationPath</span><span>=</span>&quot;<span>C:\Program Files (x86)\Evernote\Evernote\Evernote.exe</span>&quot;<span> </span><span>Title</span><span>=</span>&quot;<span>Evernote</span>&quot;<span> </span><span>Category</span><span>=</span>&quot;<span>Office</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Task</span><span> </span><span>ApplicationPath</span><span>=</span>&quot;<span>C:\Users\AMuradov\AppData\Local\Apps\Evernote\Evernote\Evernote.exe</span>&quot;<span> </span><span>Title</span><span>=</span>&quot;<span>Evernote</span>&quot;<span> </span><span>Category</span><span>=</span>&quot;<span>Office</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Task</span><span> </span><span>ApplicationPath</span><span>=</span>&quot;<span>D:\Pub\Tools\Notepad++\notepad++.exe</span>&quot;<span> </span><span>Title</span><span>=</span>&quot;<span>Notepad++</span>&quot;<span> </span><span>Category</span><span>=</span>&quot;<span>Office</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Task</span><span> </span><span>ApplicationPath</span><span>=</span>&quot;<span>D:\Projects\TTK\AMuradov\AdHelper\AdHelper.App\bin\Release\AdHelper.App.exe</span>&quot;<span> </span><span>Title</span><span>=</span>&quot;<span>AdHelper.App</span>&quot;<span> </span><span>Category</span><span>=</span>&quot;<span>Programming</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Task</span><span> </span><span>ApplicationPath</span><span>=</span>&quot;<span>D:\Pub\Tools\Far\x64\FarEmu\ConEmu64.exe</span>&quot;<span> </span><span>Title</span><span>=</span>&quot;<span>Far x64</span>&quot;<span> </span><span>Category</span><span>=</span>&quot;<span>Programming</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Task</span><span> </span><span>ApplicationPath</span><span>=</span>&quot;<span>D:\Pub\Tools\SQL Tools\SQL.Manager\MsManager.exe</span>&quot;<span> </span><span>Title</span><span>=</span>&quot;<span>MsManager</span>&quot;<span> </span><span>Category</span><span>=</span>&quot;<span>Programming</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Task</span><span> </span><span>ApplicationPath</span><span>=</span>&quot;<span>D:\Pub\Tools\Rad Software Regular Expression Designer\Rad.RegexDesigner.exe</span>&quot;<span> </span><span>Title</span><span>=</span>&quot;<span>Rad.RegexDesigner</span>&quot;<span> </span><span>Category</span><span>=</span>&quot;<span>Programming</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Task</span><span> </span><span>ApplicationPath</span><span>=</span>&quot;<span>C:\Program Files (x86)\Microsoft SQL Server\100\Tools\Binn\VSShell\Common7\IDE\Ssms.exe</span>&quot;<span> </span><span>Title</span><span>=</span>&quot;<span>Sql Management Studio</span>&quot;<span> </span><span>Category</span><span>=</span>&quot;<span>Programming</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Task</span><span> </span><span>ApplicationPath</span><span>=</span>&quot;<span>C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe</span>&quot;<span> </span><span>Title</span><span>=</span>&quot;<span>Visual Studio 2010</span>&quot;<span> </span><span>Category</span><span>=</span>&quot;<span>Programming</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Task</span><span> </span><span>ApplicationPath</span><span>=</span>&quot;<span>C:\Users\\uc1Артем\AppData\Local\Google\Chrome\Application\chrome.exe</span>&quot;<span> </span><span>Title</span><span>=</span>&quot;<span>Chrome</span>&quot;<span> </span><span>Category</span><span>=</span>&quot;<span>Web</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Task</span><span> </span><span>ApplicationPath</span><span>=</span>&quot;<span>C:\Users\AMuradov\AppData\Local\Google\Chrome\Application\chrome.exe</span>&quot;<span> </span><span>Title</span><span>=</span>&quot;<span>Chrome</span>&quot;<span> </span><span>Category</span><span>=</span>&quot;<span>Web</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Task</span><span> </span><span>ApplicationPath</span><span>=</span>&quot;<span>C:\Program Files (x86)\Mozilla Firefox\firefox.exe</span>&quot;<span> </span><span>Title</span><span>=</span>&quot;<span>Fierfox</span>&quot;<span> </span><span>Description</span><span>=</span>&quot;<span>Web</span>&quot;<span> </span><span>Category</span><span>=</span>&quot;<span>Web</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Task</span><span> </span><span>ApplicationPath</span><span>=</span>&quot;<span>C:\Program Files (x86)\Internet Explorer\iexplore.exe</span>&quot;<span> </span><span>Title</span><span>=</span>&quot;<span>IE</span>&quot;<span> </span><span>Category</span><span>=</span>&quot;<span>Web</span>&quot;<span> /&gt;</span></li>
 <li><span>&lt;/</span><span>ArrayOfTask</span><span>&gt;</span></li>
 </ol></div></div><br/>
Далее, мне для моей сущности Task нужна была ViewModel - именно её я буду привязывать к интерфейсу. <br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>public</span> <span>class</span> <span>TaskViewModel</span></li>
 <li>{</li>
 <li> <span>private</span> <span>readonly</span> <span>Task</span> _task;</li>
 <li>&#160;</li>
 <li> <span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li> <span>///</span><span> Конструктор. Принимает Task и заполняет нужные поля данными. Также инициализирует команду запуска приложения.</span></li>
 <li> <span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li> <span>///</span><span> </span><span>&lt;param name=&quot;task&quot;&gt;&lt;/param&gt;</span></li>
 <li> <span>public</span> TaskViewModel( <span>Task</span> task)</li>
 <li> {</li>
 <li> _task = task;</li>
 <li> </li>
 <li> ApplicationPath = _task.ApplicationPath;</li>
 <li> Category = _task.Category;</li>
 <li> Description = _task.Description;</li>
 <li> Title = _task.Title;</li>
 <li>&#160;</li>
 <li> <span>// Запуск приложения</span></li>
 <li> StartCommand = <span>new</span> <span>RelayCommand</span>(()=&gt;</li>
 <li> {</li>
 <li> <span>if</span> (<span>File</span>.Exists(ApplicationPath))</li>
 <li> <span>Process</span>.Start(ApplicationPath);</li>
 <li> },</li>
 <li> ()=&gt; <span>File</span>.Exists(ApplicationPath));</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li> <span>///</span><span> Применяется для получения экземпляра Task - понадобится при сохранении информации из интерфейса в файл</span></li>
 <li> <span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li> <span>///</span><span> </span><span>&lt;returns&gt;&lt;/returns&gt;</span></li>
 <li> <span>public</span> <span>Task</span> GetTask()</li>
 <li> {</li>
 <li> <span>return</span> <span>new</span> <span>Task</span></li>
 <li> {</li>
 <li> <span>// Это поле нельзя изменять через интерфейс. Для этого я и оставил переменную _task</span></li>
 <li> ApplicationPath = _task.ApplicationPath,</li>
 <li> Category = Category,</li>
 <li> Description = Description,</li>
 <li> Title = Title</li>
 <li> };</li>
 <li> }</li>
 <li>&#160;</li>
 <li> </li>
 <li> <span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li> <span>///</span><span> Публичные поля</span></li>
 <li> <span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li> <span>public</span> <span>string</span> ApplicationPath { <span>get</span>; <span>set</span>; }</li>
 <li> <span>public</span> <span>string</span> Title { <span>get</span>; <span>set</span>; }</li>
 <li> <span>public</span> <span>string</span> Description { <span>get</span>; <span>set</span>; }</li>
 <li> <span>public</span> <span>string</span> Category { <span>get</span>; <span>set</span>; }</li>
 <li> </li>
 <li> <span>// Команды</span></li>
 <li> <span>public</span> <span>ICommand</span> StartCommand { <span>get</span>; <span>set</span>; }</li>
 <li> </li>
 <li> <span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li> <span>///</span><span> Получение иконки. Используется для показа иконки приложения.</span></li>
 <li> <span>///</span><span> Как ни старался, так и не решил проблему с цветом. То есть у результирующей иконки палитра цветов отличается от оригинальной.</span></li>
 <li> <span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li> <span>private</span> <span>object</span> _icon;</li>
 <li> <span>public</span> <span>object</span> Icon</li>
 <li> {</li>
 <li> <span>get</span></li>
 <li> {</li>
 <li> <span>if</span> (_icon == <span>null</span>)</li>
 <li> {</li>
 <li> <span>try</span></li>
 <li> {</li>
 <li> <span>var</span> ico = System.Drawing.<span>Icon</span>.ExtractAssociatedIcon(ApplicationPath);</li>
 <li>&#160;</li>
 <li> <span>if</span> (ico != <span>null</span>)</li>
 <li> {</li>
 <li> <span>using</span> (<span>var</span> strm = <span>new</span> <span>MemoryStream</span>())</li>
 <li> {</li>
 <li> ico.Save(strm);</li>
 <li> <span>var</span> ibd = <span>new</span> <span>IconBitmapDecoder</span>(strm, <span>BitmapCreateOptions</span>.PreservePixelFormat, <span>BitmapCacheOption</span>.Default);</li>
 <li> <span>var</span> frame = ibd.Frames.FirstOrDefault();</li>
 <li> _icon = frame;</li>
 <li> }</li>
 <li> }</li>
 <li> }</li>
 <li> <span>catch</span></li>
 <li> {</li>
 <li> _icon = <span>null</span>;</li>
 <li> }</li>
 <li> }</li>
 <li> <span>return</span> _icon;</li>
 <li> }</li>
 <li> }</li>
 <li>}</li>
 </ol></div></div><br/>
Теперь самая главная наша ViewModel. <br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 3em; padding: 0 0 0 5px"><li><span>public</span> <span>class</span> <span>MainViewModel</span> : <span>ViewModelBase</span></li>
 <li>{</li>
 <li> <span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li> <span>///</span><span> Список переходов</span></li>
 <li> <span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li> <span>readonly</span> <span>JumpList</span> _jumpList;</li>
 <li>&#160;</li>
 <li> <span>public</span> MainViewModel()</li>
 <li> {</li>
 <li> <span>// Инициализируем список и коллекцию </span></li>
 <li> _jumpList = <span>new</span> <span>JumpList</span>();</li>
 <li> <span>JumpList</span>.SetJumpList(<span>Application</span>.Current, _jumpList);</li>
 <li>&#160;</li>
 <li> _tasks = <span>new</span> <span>ObservableCollection</span>&lt;<span>TaskViewModel</span>&gt;();</li>
 <li> </li>
 <li> <span>// Загружаем из файла задачи</span></li>
 <li> Load();</li>
 <li>&#160;</li>
 <li> <span>// Обновляем список переходов</span></li>
 <li> Apply();</li>
 <li>&#160;</li>
 <li> <span>// Команда обновления списка переходов</span></li>
 <li> ApplyCommand = <span>new</span> <span>RelayCommand</span>(Apply);</li>
 <li> }</li>
 <li> </li>
 <li> <span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li> <span>///</span><span> Команды</span></li>
 <li> <span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li> <span>public</span> <span>ICommand</span> ApplyCommand { <span>get</span>; <span>set</span>; }</li>
 <li>&#160;</li>
 <li> <span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li> <span>///</span><span> Коллекция задач</span></li>
 <li> <span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li> <span>private</span> <span>ObservableCollection</span>&lt;<span>TaskViewModel</span>&gt; _tasks;</li>
 <li> <span>public</span> <span>ObservableCollection</span>&lt;<span>TaskViewModel</span>&gt; Tasks</li>
 <li> {</li>
 <li> <span>get</span> { <span>return</span> _tasks; }</li>
 <li> <span>set</span></li>
 <li> {</li>
 <li> <span>if</span> (_tasks != <span>value</span>)</li>
 <li> {</li>
 <li> _tasks = <span>value</span>;</li>
 <li> RaisePropertyChanged(<span>&quot;Tasks&quot;</span>);</li>
 <li> }</li>
 <li> }</li>
 <li> }</li>
 <li>&#160;</li>
 <li>&#160;</li>
 <li> <span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li> <span>///</span><span> Функция, перезаписывает список переходов.</span></li>
 <li> <span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li> <span>public</span> <span>void</span> Apply()</li>
 <li> {</li>
 <li> <span>// очистка существующего списка</span></li>
 <li> _jumpList.JumpItems.Clear();</li>
 <li>&#160;</li>
 <li> <span>// получаем JumpTask</span></li>
 <li> <span>var</span> jumpTasks =</li>
 <li> (<span>from</span> task <span>in</span> Tasks.Select(x=&gt;x.GetTask())</li>
 <li> <span>where</span> <span>File</span>.Exists(task.ApplicationPath)</li>
 <li> <span>orderby</span> task.Title, task.Category </li>
 <li> <span>select</span> <span>new</span> <span>JumpTask</span></li>
 <li> {</li>
 <li> Title = task.Title ?? <span>string</span>.Empty,</li>
 <li> Description = task.Description ?? <span>string</span>.Empty,</li>
 <li> ApplicationPath = task.ApplicationPath ?? <span>string</span>.Empty,</li>
 <li> IconResourcePath = task.ApplicationPath ?? <span>string</span>.Empty,</li>
 <li> WorkingDirectory = <span>Path</span>.GetDirectoryName(task.ApplicationPath),</li>
 <li> CustomCategory = task.Category ?? <span>string</span>.Empty,</li>
 <li> }).ToList();</li>
 <li> <span>// Шаманим с сортировкой. Этот код вообще не обязателен, просто мне нужен был список в определенном порядке</span></li>
 <li> jumpTasks.Reverse();</li>
 <li> <span>// добавляем все JumpTask в список jumpTasks</span></li>
 <li> jumpTasks.ForEach(_jumpList.JumpItems.Add);</li>
 <li> <span>// применяем изменения</span></li>
 <li> _jumpList.Apply();</li>
 <li> <span>// сохраняем список в файл</span></li>
 <li> Save();</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>// Сохранение списка в файл</span></li>
 <li> <span>public</span> <span>void</span> Save()</li>
 <li> {</li>
 <li> <span>Settings</span>.Instance.SetTasks(Tasks.Select(x=&gt;x.GetTask()));</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>// Загрузка списка из файла</span></li>
 <li> <span>public</span> <span>void</span> Load()</li>
 <li> {</li>
 <li> <span>try</span></li>
 <li> {</li>
 <li> <span>var</span> tasks = <span>Settings</span>.Instance.GetTasks();</li>
 <li> <span>foreach</span> (<span>var</span> task <span>in</span> tasks.OrderBy(x=&gt;x.Category).ThenBy(x=&gt;x.Title))</li>
 <li> {</li>
 <li> _tasks.Add(<span>new</span> <span>TaskViewModel</span>(task));</li>
 <li> }</li>
 <li> }</li>
 <li> <span>catch</span></li>
 <li> {</li>
 <li> _tasks = <span>new</span> <span>ObservableCollection</span>&lt;<span>TaskViewModel</span>&gt;();</li>
 <li> }</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>// Добавление нового элемента в список. </span></li>
 <li> <span>public</span> <span>void</span> Add(<span>string</span> fileName)</li>
 <li> {</li>
 <li> <span>var</span> task = <span>new</span> <span>Task</span> { ApplicationPath = fileName, Category = <span>string</span>.Empty, Title = <span>Path</span>.GetFileNameWithoutExtension(fileName) };</li>
 <li> _tasks.Add(<span>new</span> <span>TaskViewModel</span>(task));</li>
 <li> }</li>
 <li>}</li>
 </ol></div></div><br/>
Осталось только прибиндить это всё к гриду. Вот как я это сделал:<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>&lt;</span><span>DataGrid</span> <span> x</span><span>:</span><span>Name</span><span>=&quot;dg&quot;</span></li>
 <li> <span>Grid.Row</span><span>=&quot;2&quot;</span><span> ItemsSource</span><span>=&quot;{</span><span>Binding</span><span> Tasks</span><span>,</span><span> Mode</span><span>=TwoWay}&quot;</span><span> AutoGenerateColumns</span><span>=&quot;False&quot;</span><span> CanUserReorderColumns</span><span>=&quot;True&quot;</span><span> CanUserResizeColumns</span><span>=&quot;True&quot;</span> </li>
 <li> <span> CanUserResizeRows</span><span>=&quot;False&quot;</span><span> CanUserSortColumns</span><span>=&quot;True&quot;</span><span> CanUserAddRows</span><span>=&quot;True&quot;</span><span> CanUserDeleteRows</span><span>=&quot;True&quot;</span> <span> Margin</span><span>=&quot;5&quot;</span> <span> &gt;</span></li>
 <li> <span>&lt;</span><span>DataGrid.Columns</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>DataGridTemplateColumn</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>DataGridTemplateColumn.CellTemplate</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>DataTemplate</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>Image</span> <span> Source</span><span>=&quot;{</span><span>Binding</span><span> Icon</span><span>,</span><span> Mode</span><span>=OneWay}&quot;</span><span> Stretch</span><span>=&quot;Uniform&quot;</span><span> Width</span><span>=&quot;16&quot;&gt;&lt;/</span><span>Image</span><span>&gt;</span></li>
 <li> <span>&lt;/</span><span>DataTemplate</span><span>&gt;</span></li>
 <li> <span>&lt;/</span><span>DataGridTemplateColumn.CellTemplate</span><span>&gt;</span></li>
 <li> <span>&lt;/</span><span>DataGridTemplateColumn</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>DataGridTextColumn</span><span> Header</span><span>=&quot;Category&quot;</span> <span> Binding</span><span>=&quot;{</span><span>Binding</span><span> Category</span><span>,</span><span> Mode</span><span>=TwoWay}&quot;</span><span> Width</span><span>=&quot;Auto&quot;&gt;&lt;/</span><span>DataGridTextColumn</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>DataGridTextColumn</span><span> Header</span><span>=&quot;Title&quot;</span> <span> Binding</span><span>=&quot;{</span><span>Binding</span><span> Title</span><span>,</span><span> Mode</span><span>=TwoWay}&quot;</span><span> Width</span><span>=&quot;Auto&quot;&gt;&lt;/</span><span>DataGridTextColumn</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>DataGridTextColumn</span><span> Header</span><span>=&quot;Description&quot;</span><span> Binding</span><span>=&quot;{</span><span>Binding</span><span> Description</span><span>,</span><span> Mode</span><span>=TwoWay}&quot;</span><span> Width</span><span>=&quot;Auto&quot;&gt;&lt;/</span><span>DataGridTextColumn</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>DataGridTemplateColumn</span><span> Header</span><span>=&quot;ApplicationPath&quot;</span><span> Width</span><span>=&quot;*&quot;&gt;</span></li>
 <li> <span>&lt;</span><span>DataGridTemplateColumn.CellTemplate</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>DataTemplate</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>Button</span> <span> VerticalAlignment</span><span>=&quot;Stretch&quot;</span><span> HorizontalAlignment</span><span>=&quot;Stretch&quot;</span><span> Margin</span><span>=&quot;2&quot;</span><span> CommandParameter</span><span>=&quot;{</span><span>Binding</span><span> ApplicationPath}</span><span>&quot;</span><span> Command</span><span>=&quot;{</span><span>Binding</span><span> StartCommand}</span><span>&quot; &gt;</span></li>
 <li> <span>&lt;</span><span>Button.Background</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>SolidColorBrush</span><span> Color</span><span>=&quot;Transparent&quot;&gt;&lt;/</span><span>SolidColorBrush</span><span>&gt;</span></li>
 <li> <span>&lt;/</span><span>Button.Background</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>Button.Content</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>TextBlock</span> <span> Text</span><span>=&quot;{</span><span>Binding</span><span> ApplicationPath</span><span>,</span><span> Mode</span><span>=OneWay}&quot;&gt;&lt;/</span><span>TextBlock</span><span>&gt;</span></li>
 <li> <span>&lt;/</span><span>Button.Content</span><span>&gt;</span></li>
 <li> <span>&lt;/</span><span>Button</span><span>&gt;</span></li>
 <li> <span>&lt;/</span><span>DataTemplate</span><span>&gt;</span></li>
 <li> <span>&lt;/</span><span>DataGridTemplateColumn.CellTemplate</span><span>&gt;</span></li>
 <li> <span>&lt;/</span><span>DataGridTemplateColumn</span><span>&gt; </span></li>
 <li> <span>&lt;/</span><span>DataGrid.Columns</span><span>&gt;</span></li>
 <li><span>&lt;/</span><span>DataGrid</span><span>&gt;</span></li>
 </ol></div></div><br/>
Благодаря двухсторонней привязке, у меня есть возможность редактировать мой список задач. Ещё я добавил панель инструментов с одной кнопкой - для сохранения и обновления списка переходов.<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>&lt;</span><span>ToolBar</span><span> Grid.Row</span><span>=&quot;1&quot;&gt; </span></li>
 <li> <span>&lt;</span><span>Button</span><span> Command</span><span>=&quot;{</span><span>Binding</span><span> ApplyCommand}</span><span>&quot;&gt;</span></li>
 <li> <span>&lt;</span><span>Image</span><span> Source</span><span>=&quot;Images/apply.png&quot;</span><span> Height</span><span>=&quot;16&quot;/&gt;</span></li>
 <li> <span>&lt;/</span><span>Button</span><span>&gt; </span></li>
 <li><span>&lt;/</span><span>ToolBar</span><span>&gt;</span></li>
 </ol></div></div><br/>
Итак, теперь я могу редактировать мои задачи прямо в интерфейсе. Но я ещё не могу добавить их туда. Я решил использовать событие Drop главного окна, чтобы легко добавлять новые записи в мой список задач.<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>private</span> <span>void</span> WindowDrop(<span>object</span> sender, <span>DragEventArgs</span> e)</li>
 <li>{</li>
 <li> <span>if</span> (e.Data <span>is</span> <span>DataObject</span> &amp;&amp; ((<span>DataObject</span>)e.Data).ContainsFileDropList())</li>
 <li> {</li>
 <li> <span>foreach</span> (<span>string</span> filePath <span>in</span> ((<span>DataObject</span>)e.Data).GetFileDropList())</li>
 <li> {</li>
 <li> <span>if</span> (<span>File</span>.Exists(filePath))</li>
 <li> _model.Add(filePath);</li>
 <li> }</li>
 <li> }</li>
 <li>}</li>
 </ol></div></div><br/>
В итоге, я получил приложение, которое позволяет синхронизировать мои списки переходов между всеми компьютерами. Также я предусмотрел, что если приложения, которое я указал на первом ПК, на втором ПК нет или путь к нему другой, - то ссылка на него на втором ПК не появится. Вот скрины моих результатов:<br/>
<br/>
<div style="text-align: center"><!--noindex--><a href="http://1.bp.blogspot.com/-8-aYW4bYi-g/TxBKtWWpg1I/AAAAAAAAC8Q/dzpbhUQp46c/s1600/2.png" rel="nofollow" style="margin-left: 1em; margin-right: 1em"><img src="http://1.bp.blogspot.com/-8-aYW4bYi-g/TxBKtWWpg1I/AAAAAAAAC8Q/dzpbhUQp46c/s1600/2.png" border="0"/></a><!--/noindex--></div><div style="text-align: center"><!--noindex--><a href="http://2.bp.blogspot.com/-8MGScubW_6c/TxBMs8YckxI/AAAAAAAAC8o/Fq60Sb6ysVE/s1600/3.png" rel="nofollow" style="margin-left: 1em; margin-right: 1em"><img src="http://2.bp.blogspot.com/-8MGScubW_6c/TxBMs8YckxI/AAAAAAAAC8o/Fq60Sb6ysVE/s1600/3.png" border="0"/></a><!--/noindex--></div><div style="text-align: center"><!--noindex--><a href="http://4.bp.blogspot.com/-nLjTJcUpW8I/TxBm9lLf4RI/AAAAAAAAC80/xkErDEErgD4/s1600/4.png" rel="nofollow" style="margin-left: 1em; margin-right: 1em"><img src="http://4.bp.blogspot.com/-nLjTJcUpW8I/TxBm9lLf4RI/AAAAAAAAC80/xkErDEErgD4/s400/4.png" border="0"/></a><!--/noindex--></div><br/>
Теперь об ограничениях. Моя программа никак не работает с папками, она никак не работает с аргументами приложений, и вдобавок ей нужны именно *.exe файлы, ярлыки тоже никак не отработают. Меня все эти ограничения вполне устраивают, поэтому я ими не занимался. <br/>
<br/>
Я было хотел выложить код программы на кодеплекс, но, как оказалось (и что, собственно, очевидно), использовать списки переходов для быстрого запуска программ идея не новая. Просто той функциональности, что была нужна мне, я в других программах не нашел, да и пощупать возможности панели задач уже давно чесались руки. Поэтому я свои исходники публиковать не буду (к тому же, я почти весь код в статье написал), а просто приведу несколько программ, которые решают подобные задачи.<br/>
<ul><li><!--noindex--><a href="http://en.www.ali.dj/jumplist-launcher/" rel="nofollow">Jumplist-Launcher</a><!--/noindex--></li>
 <li><!--noindex--><a href="http://jumplaunch.codeplex.com/" rel="nofollow">JumpLaunch</a><!--/noindex--></li>
 <li><!--noindex--><a href="http://browserchooser.codeplex.com/" rel="nofollow">Browser Chooser</a><!--/noindex--></li>
 <li><!--noindex--><a href="http://www.addictivetips.com/windows-tips/create-and-categorize-jump-list-items-with-seven-jump-launcher/" rel="nofollow">Seven Jump</a><!--/noindex--></li>
 </ul>Ещё ссылки:<br/>
<ul><li><!--noindex--><a href="http://windows.microsoft.com/ru-RU/windows7/products/features/jump-lists" rel="nofollow">Общее описание списков переходов</a><!--/noindex--></li>
 <li><!--noindex--><a href="http://system-administrators.info/?p=3494" rel="nofollow">Windows 7: Как изменить количество элементов в Jump List</a><!--/noindex--></li>
 <li><!--noindex--><a href="http://msdn.microsoft.com/ru-ru/library/system.windows.shell.jumplist.aspx" rel="nofollow">JumpList MSDN</a><!--/noindex--></li>
 <li><!--noindex--><a href="http://habrahabr.ru/tag/windows 7 taskbar/" rel="nofollow">О панели задач на Хабре</a><!--/noindex--></li>
 </ul><br/>
На этом всё. Всем спасибо.<br/>
<br/>
<b>UPD.</b> Думаю, следует пояснить. В классе TaskViewModel команда StartCommand запускает приложение. Это я сделал только для того, чтобы у меня была возможность запустить приложение из моей программы. К списку переходов эта команда не имеет никакого отношения. Вся работа со списком переходов в классе MainViewModel<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li><span>///</span><span> Функция, перезаписывает список переходов.</span></li>
 <li><span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li><span>public</span> <span>void</span> Apply()</li>
 <li>{</li>
 <li> <span>// очистка существующего списка</span></li>
 <li> _jumpList.JumpItems.Clear();</li>
 <li>&#160;</li>
 <li> <span>// получаем JumpTask</span></li>
 <li> <span>var</span> jumpTasks =</li>
 <li> (<span>from</span> task <span>in</span> Tasks.Select(x=&gt;x.GetTask())</li>
 <li> <span>where</span> <span>File</span>.Exists(task.ApplicationPath)</li>
 <li> <span>orderby</span> task.Title, task.Category </li>
 <li> <span>select</span> <span>new</span> <span>JumpTask</span></li>
 <li> {</li>
 <li> Title = task.Title ?? <span>string</span>.Empty,</li>
 <li> Description = task.Description ?? <span>string</span>.Empty,</li>
 <li> ApplicationPath = task.ApplicationPath ?? <span>string</span>.Empty,</li>
 <li> IconResourcePath = task.ApplicationPath ?? <span>string</span>.Empty,</li>
 <li> WorkingDirectory = <span>Path</span>.GetDirectoryName(task.ApplicationPath),</li>
 <li> CustomCategory = task.Category ?? <span>string</span>.Empty,</li>
 <li> }).ToList();</li>
 <li> <span>// Шаманим с сортировкой. Этот код вообще не обязателен, просто мне нужен был список в определенном порядке</span></li>
 <li> jumpTasks.Reverse();</li>
 <li> <span>// добавляем все JumpTask в список jumpTasks</span></li>
 <li> jumpTasks.ForEach(_jumpList.JumpItems.Add);</li>
 <li> <span>// применяем изменения</span></li>
 <li> _jumpList.Apply();</li>
 <li> <span>// сохраняем список в файл</span></li>
 <li> Save();</li>
 <li>}</li>
 </ol></div></div><br/>
Весь остальной код относится к работе непосредственно самой программы. Список переходов же доступен и тогда, когда программа не запущена.<br/>
<br/>
</div><div><img src="https://blogger.googleusercontent.com/tracker/8897990838383834685-6941989845948170241?l=tym32167.blogspot.com" width="1px" height="1px" border="0"/></div>]]></description>
      <category><![CDATA[WPF]]></category>
      <category><![CDATA[.NET]]></category>
      <category><![CDATA[Windows 7 Taskbar]]></category>
      <category><![CDATA[C#]]></category>
      <guid>http://tym32167.blogspot.com/2012/01/blog-post.html</guid>
      <pubDate>Fri, 13 Jan 2012 17:39:00 UT</pubDate>
      <dc:creator><![CDATA[tym32167]]></dc:creator>
    </item>
    <item>
      <title><![CDATA[Программируем списки переходов или как сократить количество ярлыков на рабочем столе]]></title>
      <link>http://microgeek.ru/blogs/tym32167/1725/</link>
      <description><![CDATA[<div style="text-align: left">Здравствуйте. Я думаю, у каждого программиста есть свой набор примочек, программ, которые делают процесс работы проще и приятней. Сегодня речь пойдет об одной из таких программ, а точнее о том, как использовать списки переходов (jump lists), дабы уменьшить количество ярлыков на рабочем столе. Вот, что мы получим в итоге:<br/>
<div style="text-align: center"><!--noindex--><a href="http://1.bp.blogspot.com/-1Ac1i0dYQQ4/TxAumisMMaI/AAAAAAAAC8E/1_kpiSNajuY/s1600/1.png" rel="nofollow" style="margin-left: 1em; margin-right: 1em"><img src="http://1.bp.blogspot.com/-1Ac1i0dYQQ4/TxAumisMMaI/AAAAAAAAC8E/1_kpiSNajuY/s400/1.png" width="210px" height="400px" border="0"/></a><!--/noindex--></div>За подробностями прошу под кат.<br/>
<a name="more" rel="nofollow"></a><br/>
<br/>
Итак, начальные условия:<br/>
1. У меня есть около 15 программ, которыми я пользуюсь часто (хотя бы раз в день). Хочу иметь возможность запускать эти программы быстро и удобно<br/>
2. Большая часть этих программ лежит в папке, которая синхронизируется между всеми моими компами/виртуалками<br/>
3. Общее между всеми компами то, что там везде установлена Windows 7<br/>
<br/>
Задача:<br/>
Написать программу, которая также будет синхронизирована между всеми компами и хранить информацию о запускаемых приложениях, давая возможность запускать эти приложения.<br/>
<br/>
Как я это вижу:<br/>
<br/>
Для каждой программы надо будет сделать описание (путь к exe файлу, название программы, описание и категория - это как минимум). Набор этих описаний я буду хранить в файле в той же папке что и саму программу. Тогда, благодаря синхронизации, у меня будет один общий список запускаемых программ для всех компьютеров. В самой программе нужно реализовать механизм заполнения списков переходов, запуска приложения из программы, ну и возможность редактирования названия и описания приложения. <br/>
<br/>
Инструменты:<br/>
1. <!--noindex--><a href="http://windows.microsoft.com/ru-RU/windows7/products/features/jump-lists" rel="nofollow">Списки переходов</a><!--/noindex--><br/>
2. Я выбрал WPF, так как это моя слабая сторона. Повышаю опыт.<br/>
3. <!--noindex--><a href="http://mvvmlight.codeplex.com/" rel="nofollow">MVVM Light Toolkit</a><!--/noindex--><br/>
<br/>
Ну, вроде всё. Поехали!<br/>
<br/>
Для начала я набросал класс этого описания программы<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>namespace</span> TaskStart.Tasks</li>
 <li>{</li>
 <li> [<span>Serializable</span>]</li>
 <li> <span>public</span> <span>class</span> <span>Task</span></li>
 <li> {</li>
 <li> [<span>XmlAttribute</span>]</li>
 <li> <span>public</span> <span>string</span> ApplicationPath { <span>get</span>; <span>set</span>; }</li>
 <li>&#160;</li>
 <li> [<span>XmlAttribute</span>]</li>
 <li> <span>public</span> <span>string</span> Title { <span>get</span>; <span>set</span>; }</li>
 <li>&#160;</li>
 <li> [<span>XmlAttribute</span>]</li>
 <li> <span>public</span> <span>string</span> Description { <span>get</span>; <span>set</span>; }</li>
 <li>&#160;</li>
 <li> [<span>XmlAttribute</span>]</li>
 <li> <span>public</span> <span>string</span> Category { <span>get</span>; <span>set</span>; }</li>
 <li> }</li>
 <li>}</li>
 </ol></div></div><br/>
Тут ничего сложного. Далее, мне надо было определить механизм сохранения/загрузки. Я сделал простой класс Settings. Синглтоном я его сделал ради забавы, мог бы реализовать и по другому, но мне так больше нравится. Комментариев я не писал, так как код ну очень простой.<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>public</span> <span>class</span> <span>Settings</span></li>
 <li>{</li>
 <li> <span>private</span> <span>const</span> <span>string</span> SettingsFileName = <span>&quot;Settings.xml&quot;</span>;</li>
 <li>&#160;</li>
 <li> <span>private</span> Settings()</li>
 <li> {</li>
 <li>&#160;</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>private</span> <span>static</span> <span>Settings</span> _instance;</li>
 <li> <span>public</span> <span>static</span> <span>Settings</span> Instance</li>
 <li> {</li>
 <li> <span>get</span> { <span>return</span> _instance ?? (_instance = <span>new</span> <span>Settings</span>()); }</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>public</span> <span>IEnumerable</span>&lt;<span>Task</span>&gt; GetTasks()</li>
 <li> {</li>
 <li> <span>var</span> result = <span>new</span> <span>List</span>&lt;<span>Task</span>&gt;();</li>
 <li> <span>if</span> (<span>File</span>.Exists(SettingsFileName))</li>
 <li> {</li>
 <li> <span>try</span></li>
 <li> {</li>
 <li> <span>var</span> xmlSer = <span>new</span> <span>XmlSerializer</span>(<span>typeof</span>(<span>List</span>&lt;<span>Task</span>&gt;));</li>
 <li> <span>using</span> (<span>var</span> sr = <span>new</span> <span>StreamReader</span>(SettingsFileName))</li>
 <li> {</li>
 <li> <span>var</span> res = xmlSer.Deserialize(sr) <span>as</span> <span>List</span>&lt;<span>Task</span>&gt;;</li>
 <li> result = res ?? <span>new</span> <span>List</span>&lt;<span>Task</span>&gt;();</li>
 <li> }</li>
 <li> }</li>
 <li> <span>catch</span> (<span>Exception</span>)</li>
 <li> {</li>
 <li> <span>return</span> result;</li>
 <li> }</li>
 <li> }</li>
 <li> <span>return</span> result;</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>public</span> <span>void</span> SetTasks(<span>IEnumerable</span>&lt;<span>Task</span>&gt; tasks)</li>
 <li> {</li>
 <li> <span>var</span> taskList = tasks.ToList();</li>
 <li> <span>using</span> (<span>var</span> sw = <span>new</span> <span>StreamWriter</span>(SettingsFileName, <span>false</span>))</li>
 <li> {</li>
 <li> <span>var</span> xmlSer = <span>new</span> <span>XmlSerializer</span>(<span>typeof</span>(<span>List</span>&lt;<span>Task</span>&gt;));</li>
 <li> xmlSer.Serialize(sw, taskList);</li>
 <li> }</li>
 <li> }</li>
 <li>}</li>
 </ol></div></div><br/>
Вот пример полученного на выходе XML<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>&lt;?</span><span>xml</span><span> </span><span>version</span><span>=</span>&quot;<span>1.0</span>&quot;<span> </span><span>encoding</span><span>=</span>&quot;<span>utf-8</span>&quot;<span>?&gt;</span></li>
 <li><span>&lt;</span><span>ArrayOfTask</span><span> </span><span>xmlns:xsi</span><span>=</span>&quot;<span>http://www.w3.org/2001/XMLSchema-instance</span>&quot;<span> </span><span>xmlns:xsd</span><span>=</span>&quot;<span>http://www.w3.org/2001/XMLSchema</span>&quot;<span>&gt;</span></li>
 <li> <span>&lt;</span><span>Task</span><span> </span><span>ApplicationPath</span><span>=</span>&quot;<span>D:\Pub\Tools\foobar2000\foobar2000.exe</span>&quot;<span> </span><span>Title</span><span>=</span>&quot;<span>foobar2000</span>&quot;<span> </span><span>Category</span><span>=</span>&quot;<span>Entertainment</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Task</span><span> </span><span>ApplicationPath</span><span>=</span>&quot;<span>D:\Pub\Tools\The KMPlayer\KMPlayer.exe</span>&quot;<span> </span><span>Title</span><span>=</span>&quot;<span>KMPlayer</span>&quot;<span> </span><span>Category</span><span>=</span>&quot;<span>Entertainment</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Task</span><span> </span><span>ApplicationPath</span><span>=</span>&quot;<span>D:\Pub\Miranda IM\MirandaPortable.exe</span>&quot;<span> </span><span>Title</span><span>=</span>&quot;<span>Miranda</span>&quot;<span> </span><span>Category</span><span>=</span>&quot;<span>Messaging</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Task</span><span> </span><span>ApplicationPath</span><span>=</span>&quot;<span>C:\Program Files (x86)\Skype\Phone\Skype.exe</span>&quot;<span> </span><span>Title</span><span>=</span>&quot;<span>Skype</span>&quot;<span> </span><span>Category</span><span>=</span>&quot;<span>Messaging</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Task</span><span> </span><span>ApplicationPath</span><span>=</span>&quot;<span>D:\Pub\Tools\DotNetNotepad\DotNetNotepad.UI.exe</span>&quot;<span> </span><span>Title</span><span>=</span>&quot;<span>DotNetNotepad</span>&quot;<span> </span><span>Category</span><span>=</span>&quot;<span>Office</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Task</span><span> </span><span>ApplicationPath</span><span>=</span>&quot;<span>C:\Program Files (x86)\Evernote\Evernote\Evernote.exe</span>&quot;<span> </span><span>Title</span><span>=</span>&quot;<span>Evernote</span>&quot;<span> </span><span>Category</span><span>=</span>&quot;<span>Office</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Task</span><span> </span><span>ApplicationPath</span><span>=</span>&quot;<span>C:\Users\AMuradov\AppData\Local\Apps\Evernote\Evernote\Evernote.exe</span>&quot;<span> </span><span>Title</span><span>=</span>&quot;<span>Evernote</span>&quot;<span> </span><span>Category</span><span>=</span>&quot;<span>Office</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Task</span><span> </span><span>ApplicationPath</span><span>=</span>&quot;<span>D:\Pub\Tools\Notepad++\notepad++.exe</span>&quot;<span> </span><span>Title</span><span>=</span>&quot;<span>Notepad++</span>&quot;<span> </span><span>Category</span><span>=</span>&quot;<span>Office</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Task</span><span> </span><span>ApplicationPath</span><span>=</span>&quot;<span>D:\Projects\TTK\AMuradov\AdHelper\AdHelper.App\bin\Release\AdHelper.App.exe</span>&quot;<span> </span><span>Title</span><span>=</span>&quot;<span>AdHelper.App</span>&quot;<span> </span><span>Category</span><span>=</span>&quot;<span>Programming</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Task</span><span> </span><span>ApplicationPath</span><span>=</span>&quot;<span>D:\Pub\Tools\Far\x64\FarEmu\ConEmu64.exe</span>&quot;<span> </span><span>Title</span><span>=</span>&quot;<span>Far x64</span>&quot;<span> </span><span>Category</span><span>=</span>&quot;<span>Programming</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Task</span><span> </span><span>ApplicationPath</span><span>=</span>&quot;<span>D:\Pub\Tools\SQL Tools\SQL.Manager\MsManager.exe</span>&quot;<span> </span><span>Title</span><span>=</span>&quot;<span>MsManager</span>&quot;<span> </span><span>Category</span><span>=</span>&quot;<span>Programming</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Task</span><span> </span><span>ApplicationPath</span><span>=</span>&quot;<span>D:\Pub\Tools\Rad Software Regular Expression Designer\Rad.RegexDesigner.exe</span>&quot;<span> </span><span>Title</span><span>=</span>&quot;<span>Rad.RegexDesigner</span>&quot;<span> </span><span>Category</span><span>=</span>&quot;<span>Programming</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Task</span><span> </span><span>ApplicationPath</span><span>=</span>&quot;<span>C:\Program Files (x86)\Microsoft SQL Server\100\Tools\Binn\VSShell\Common7\IDE\Ssms.exe</span>&quot;<span> </span><span>Title</span><span>=</span>&quot;<span>Sql Management Studio</span>&quot;<span> </span><span>Category</span><span>=</span>&quot;<span>Programming</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Task</span><span> </span><span>ApplicationPath</span><span>=</span>&quot;<span>C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe</span>&quot;<span> </span><span>Title</span><span>=</span>&quot;<span>Visual Studio 2010</span>&quot;<span> </span><span>Category</span><span>=</span>&quot;<span>Programming</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Task</span><span> </span><span>ApplicationPath</span><span>=</span>&quot;<span>C:\Users\\uc1Артем\AppData\Local\Google\Chrome\Application\chrome.exe</span>&quot;<span> </span><span>Title</span><span>=</span>&quot;<span>Chrome</span>&quot;<span> </span><span>Category</span><span>=</span>&quot;<span>Web</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Task</span><span> </span><span>ApplicationPath</span><span>=</span>&quot;<span>C:\Users\AMuradov\AppData\Local\Google\Chrome\Application\chrome.exe</span>&quot;<span> </span><span>Title</span><span>=</span>&quot;<span>Chrome</span>&quot;<span> </span><span>Category</span><span>=</span>&quot;<span>Web</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Task</span><span> </span><span>ApplicationPath</span><span>=</span>&quot;<span>C:\Program Files (x86)\Mozilla Firefox\firefox.exe</span>&quot;<span> </span><span>Title</span><span>=</span>&quot;<span>Fierfox</span>&quot;<span> </span><span>Description</span><span>=</span>&quot;<span>Web</span>&quot;<span> </span><span>Category</span><span>=</span>&quot;<span>Web</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Task</span><span> </span><span>ApplicationPath</span><span>=</span>&quot;<span>C:\Program Files (x86)\Internet Explorer\iexplore.exe</span>&quot;<span> </span><span>Title</span><span>=</span>&quot;<span>IE</span>&quot;<span> </span><span>Category</span><span>=</span>&quot;<span>Web</span>&quot;<span> /&gt;</span></li>
 <li><span>&lt;/</span><span>ArrayOfTask</span><span>&gt;</span></li>
 </ol></div></div><br/>
Далее, мне для моей сущности Task нужна была ViewModel - именно её я буду привязывать к интерфейсу. <br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>public</span> <span>class</span> <span>TaskViewModel</span></li>
 <li>{</li>
 <li> <span>private</span> <span>readonly</span> <span>Task</span> _task;</li>
 <li>&#160;</li>
 <li> <span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li> <span>///</span><span> Конструктор. Принимает Task и заполняет нужные поля данными. Также инициализирует команду запуска приложения.</span></li>
 <li> <span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li> <span>///</span><span> </span><span>&lt;param name=&quot;task&quot;&gt;&lt;/param&gt;</span></li>
 <li> <span>public</span> TaskViewModel( <span>Task</span> task)</li>
 <li> {</li>
 <li> _task = task;</li>
 <li> </li>
 <li> ApplicationPath = _task.ApplicationPath;</li>
 <li> Category = _task.Category;</li>
 <li> Description = _task.Description;</li>
 <li> Title = _task.Title;</li>
 <li>&#160;</li>
 <li> <span>// Запуск приложения</span></li>
 <li> StartCommand = <span>new</span> <span>RelayCommand</span>(()=&gt;</li>
 <li> {</li>
 <li> <span>if</span> (<span>File</span>.Exists(ApplicationPath))</li>
 <li> <span>Process</span>.Start(ApplicationPath);</li>
 <li> },</li>
 <li> ()=&gt; <span>File</span>.Exists(ApplicationPath));</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li> <span>///</span><span> Применяется для получения экземпляра Task - понадобится при сохранении информации из интерфейса в файл</span></li>
 <li> <span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li> <span>///</span><span> </span><span>&lt;returns&gt;&lt;/returns&gt;</span></li>
 <li> <span>public</span> <span>Task</span> GetTask()</li>
 <li> {</li>
 <li> <span>return</span> <span>new</span> <span>Task</span></li>
 <li> {</li>
 <li> <span>// Это поле нельзя изменять через интерфейс. Для этого я и оставил переменную _task</span></li>
 <li> ApplicationPath = _task.ApplicationPath,</li>
 <li> Category = Category,</li>
 <li> Description = Description,</li>
 <li> Title = Title</li>
 <li> };</li>
 <li> }</li>
 <li>&#160;</li>
 <li> </li>
 <li> <span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li> <span>///</span><span> Публичные поля</span></li>
 <li> <span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li> <span>public</span> <span>string</span> ApplicationPath { <span>get</span>; <span>set</span>; }</li>
 <li> <span>public</span> <span>string</span> Title { <span>get</span>; <span>set</span>; }</li>
 <li> <span>public</span> <span>string</span> Description { <span>get</span>; <span>set</span>; }</li>
 <li> <span>public</span> <span>string</span> Category { <span>get</span>; <span>set</span>; }</li>
 <li> </li>
 <li> <span>// Команды</span></li>
 <li> <span>public</span> <span>ICommand</span> StartCommand { <span>get</span>; <span>set</span>; }</li>
 <li> </li>
 <li> <span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li> <span>///</span><span> Получение иконки. Используется для показа иконки приложения.</span></li>
 <li> <span>///</span><span> Как ни старался, так и не решил проблему с цветом. То есть у результирующей иконки палитра цветов отличается от оригинальной.</span></li>
 <li> <span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li> <span>private</span> <span>object</span> _icon;</li>
 <li> <span>public</span> <span>object</span> Icon</li>
 <li> {</li>
 <li> <span>get</span></li>
 <li> {</li>
 <li> <span>if</span> (_icon == <span>null</span>)</li>
 <li> {</li>
 <li> <span>try</span></li>
 <li> {</li>
 <li> <span>var</span> ico = System.Drawing.<span>Icon</span>.ExtractAssociatedIcon(ApplicationPath);</li>
 <li>&#160;</li>
 <li> <span>if</span> (ico != <span>null</span>)</li>
 <li> {</li>
 <li> <span>using</span> (<span>var</span> strm = <span>new</span> <span>MemoryStream</span>())</li>
 <li> {</li>
 <li> ico.Save(strm);</li>
 <li> <span>var</span> ibd = <span>new</span> <span>IconBitmapDecoder</span>(strm, <span>BitmapCreateOptions</span>.PreservePixelFormat, <span>BitmapCacheOption</span>.Default);</li>
 <li> <span>var</span> frame = ibd.Frames.FirstOrDefault();</li>
 <li> _icon = frame;</li>
 <li> }</li>
 <li> }</li>
 <li> }</li>
 <li> <span>catch</span></li>
 <li> {</li>
 <li> _icon = <span>null</span>;</li>
 <li> }</li>
 <li> }</li>
 <li> <span>return</span> _icon;</li>
 <li> }</li>
 <li> }</li>
 <li>}</li>
 </ol></div></div><br/>
Теперь самая главная наша ViewModel. <br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 3em; padding: 0 0 0 5px"><li><span>public</span> <span>class</span> <span>MainViewModel</span> : <span>ViewModelBase</span></li>
 <li>{</li>
 <li> <span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li> <span>///</span><span> Список переходов</span></li>
 <li> <span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li> <span>readonly</span> <span>JumpList</span> _jumpList;</li>
 <li>&#160;</li>
 <li> <span>public</span> MainViewModel()</li>
 <li> {</li>
 <li> <span>// Инициализируем список и коллекцию </span></li>
 <li> _jumpList = <span>new</span> <span>JumpList</span>();</li>
 <li> <span>JumpList</span>.SetJumpList(<span>Application</span>.Current, _jumpList);</li>
 <li>&#160;</li>
 <li> _tasks = <span>new</span> <span>ObservableCollection</span>&lt;<span>TaskViewModel</span>&gt;();</li>
 <li> </li>
 <li> <span>// Загружаем из файла задачи</span></li>
 <li> Load();</li>
 <li>&#160;</li>
 <li> <span>// Обновляем список переходов</span></li>
 <li> Apply();</li>
 <li>&#160;</li>
 <li> <span>// Команда обновления списка переходов</span></li>
 <li> ApplyCommand = <span>new</span> <span>RelayCommand</span>(Apply);</li>
 <li> }</li>
 <li> </li>
 <li> <span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li> <span>///</span><span> Команды</span></li>
 <li> <span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li> <span>public</span> <span>ICommand</span> ApplyCommand { <span>get</span>; <span>set</span>; }</li>
 <li>&#160;</li>
 <li> <span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li> <span>///</span><span> Коллекция задач</span></li>
 <li> <span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li> <span>private</span> <span>ObservableCollection</span>&lt;<span>TaskViewModel</span>&gt; _tasks;</li>
 <li> <span>public</span> <span>ObservableCollection</span>&lt;<span>TaskViewModel</span>&gt; Tasks</li>
 <li> {</li>
 <li> <span>get</span> { <span>return</span> _tasks; }</li>
 <li> <span>set</span></li>
 <li> {</li>
 <li> <span>if</span> (_tasks != <span>value</span>)</li>
 <li> {</li>
 <li> _tasks = <span>value</span>;</li>
 <li> RaisePropertyChanged(<span>&quot;Tasks&quot;</span>);</li>
 <li> }</li>
 <li> }</li>
 <li> }</li>
 <li>&#160;</li>
 <li>&#160;</li>
 <li> <span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li> <span>///</span><span> Функция, перезаписывает список переходов.</span></li>
 <li> <span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li> <span>public</span> <span>void</span> Apply()</li>
 <li> {</li>
 <li> <span>// очистка существующего списка</span></li>
 <li> _jumpList.JumpItems.Clear();</li>
 <li>&#160;</li>
 <li> <span>// получаем JumpTask</span></li>
 <li> <span>var</span> jumpTasks =</li>
 <li> (<span>from</span> task <span>in</span> Tasks.Select(x=&gt;x.GetTask())</li>
 <li> <span>where</span> <span>File</span>.Exists(task.ApplicationPath)</li>
 <li> <span>orderby</span> task.Title, task.Category </li>
 <li> <span>select</span> <span>new</span> <span>JumpTask</span></li>
 <li> {</li>
 <li> Title = task.Title ?? <span>string</span>.Empty,</li>
 <li> Description = task.Description ?? <span>string</span>.Empty,</li>
 <li> ApplicationPath = task.ApplicationPath ?? <span>string</span>.Empty,</li>
 <li> IconResourcePath = task.ApplicationPath ?? <span>string</span>.Empty,</li>
 <li> WorkingDirectory = <span>Path</span>.GetDirectoryName(task.ApplicationPath),</li>
 <li> CustomCategory = task.Category ?? <span>string</span>.Empty,</li>
 <li> }).ToList();</li>
 <li> <span>// Шаманим с сортировкой. Этот код вообще не обязателен, просто мне нужен был список в определенном порядке</span></li>
 <li> jumpTasks.Reverse();</li>
 <li> <span>// добавляем все JumpTask в список jumpTasks</span></li>
 <li> jumpTasks.ForEach(_jumpList.JumpItems.Add);</li>
 <li> <span>// применяем изменения</span></li>
 <li> _jumpList.Apply();</li>
 <li> <span>// сохраняем список в файл</span></li>
 <li> Save();</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>// Сохранение списка в файл</span></li>
 <li> <span>public</span> <span>void</span> Save()</li>
 <li> {</li>
 <li> <span>Settings</span>.Instance.SetTasks(Tasks.Select(x=&gt;x.GetTask()));</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>// Загрузка списка из файла</span></li>
 <li> <span>public</span> <span>void</span> Load()</li>
 <li> {</li>
 <li> <span>try</span></li>
 <li> {</li>
 <li> <span>var</span> tasks = <span>Settings</span>.Instance.GetTasks();</li>
 <li> <span>foreach</span> (<span>var</span> task <span>in</span> tasks.OrderBy(x=&gt;x.Category).ThenBy(x=&gt;x.Title))</li>
 <li> {</li>
 <li> _tasks.Add(<span>new</span> <span>TaskViewModel</span>(task));</li>
 <li> }</li>
 <li> }</li>
 <li> <span>catch</span></li>
 <li> {</li>
 <li> _tasks = <span>new</span> <span>ObservableCollection</span>&lt;<span>TaskViewModel</span>&gt;();</li>
 <li> }</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>// Добавление нового элемента в список. </span></li>
 <li> <span>public</span> <span>void</span> Add(<span>string</span> fileName)</li>
 <li> {</li>
 <li> <span>var</span> task = <span>new</span> <span>Task</span> { ApplicationPath = fileName, Category = <span>string</span>.Empty, Title = <span>Path</span>.GetFileNameWithoutExtension(fileName) };</li>
 <li> _tasks.Add(<span>new</span> <span>TaskViewModel</span>(task));</li>
 <li> }</li>
 <li>}</li>
 </ol></div></div><br/>
Осталось только прибиндить это всё к гриду. Вот как я это сделал:<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>&lt;</span><span>DataGrid</span> <span> x</span><span>:</span><span>Name</span><span>=&quot;dg&quot;</span></li>
 <li> <span>Grid.Row</span><span>=&quot;2&quot;</span><span> ItemsSource</span><span>=&quot;{</span><span>Binding</span><span> Tasks</span><span>,</span><span> Mode</span><span>=TwoWay}&quot;</span><span> AutoGenerateColumns</span><span>=&quot;False&quot;</span><span> CanUserReorderColumns</span><span>=&quot;True&quot;</span><span> CanUserResizeColumns</span><span>=&quot;True&quot;</span> </li>
 <li> <span> CanUserResizeRows</span><span>=&quot;False&quot;</span><span> CanUserSortColumns</span><span>=&quot;True&quot;</span><span> CanUserAddRows</span><span>=&quot;True&quot;</span><span> CanUserDeleteRows</span><span>=&quot;True&quot;</span> <span> Margin</span><span>=&quot;5&quot;</span> <span> &gt;</span></li>
 <li> <span>&lt;</span><span>DataGrid.Columns</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>DataGridTemplateColumn</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>DataGridTemplateColumn.CellTemplate</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>DataTemplate</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>Image</span> <span> Source</span><span>=&quot;{</span><span>Binding</span><span> Icon</span><span>,</span><span> Mode</span><span>=OneWay}&quot;</span><span> Stretch</span><span>=&quot;Uniform&quot;</span><span> Width</span><span>=&quot;16&quot;&gt;&lt;/</span><span>Image</span><span>&gt;</span></li>
 <li> <span>&lt;/</span><span>DataTemplate</span><span>&gt;</span></li>
 <li> <span>&lt;/</span><span>DataGridTemplateColumn.CellTemplate</span><span>&gt;</span></li>
 <li> <span>&lt;/</span><span>DataGridTemplateColumn</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>DataGridTextColumn</span><span> Header</span><span>=&quot;Category&quot;</span> <span> Binding</span><span>=&quot;{</span><span>Binding</span><span> Category</span><span>,</span><span> Mode</span><span>=TwoWay}&quot;</span><span> Width</span><span>=&quot;Auto&quot;&gt;&lt;/</span><span>DataGridTextColumn</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>DataGridTextColumn</span><span> Header</span><span>=&quot;Title&quot;</span> <span> Binding</span><span>=&quot;{</span><span>Binding</span><span> Title</span><span>,</span><span> Mode</span><span>=TwoWay}&quot;</span><span> Width</span><span>=&quot;Auto&quot;&gt;&lt;/</span><span>DataGridTextColumn</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>DataGridTextColumn</span><span> Header</span><span>=&quot;Description&quot;</span><span> Binding</span><span>=&quot;{</span><span>Binding</span><span> Description</span><span>,</span><span> Mode</span><span>=TwoWay}&quot;</span><span> Width</span><span>=&quot;Auto&quot;&gt;&lt;/</span><span>DataGridTextColumn</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>DataGridTemplateColumn</span><span> Header</span><span>=&quot;ApplicationPath&quot;</span><span> Width</span><span>=&quot;*&quot;&gt;</span></li>
 <li> <span>&lt;</span><span>DataGridTemplateColumn.CellTemplate</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>DataTemplate</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>Button</span> <span> VerticalAlignment</span><span>=&quot;Stretch&quot;</span><span> HorizontalAlignment</span><span>=&quot;Stretch&quot;</span><span> Margin</span><span>=&quot;2&quot;</span><span> CommandParameter</span><span>=&quot;{</span><span>Binding</span><span> ApplicationPath}</span><span>&quot;</span><span> Command</span><span>=&quot;{</span><span>Binding</span><span> StartCommand}</span><span>&quot; &gt;</span></li>
 <li> <span>&lt;</span><span>Button.Background</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>SolidColorBrush</span><span> Color</span><span>=&quot;Transparent&quot;&gt;&lt;/</span><span>SolidColorBrush</span><span>&gt;</span></li>
 <li> <span>&lt;/</span><span>Button.Background</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>Button.Content</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>TextBlock</span> <span> Text</span><span>=&quot;{</span><span>Binding</span><span> ApplicationPath</span><span>,</span><span> Mode</span><span>=OneWay}&quot;&gt;&lt;/</span><span>TextBlock</span><span>&gt;</span></li>
 <li> <span>&lt;/</span><span>Button.Content</span><span>&gt;</span></li>
 <li> <span>&lt;/</span><span>Button</span><span>&gt;</span></li>
 <li> <span>&lt;/</span><span>DataTemplate</span><span>&gt;</span></li>
 <li> <span>&lt;/</span><span>DataGridTemplateColumn.CellTemplate</span><span>&gt;</span></li>
 <li> <span>&lt;/</span><span>DataGridTemplateColumn</span><span>&gt; </span></li>
 <li> <span>&lt;/</span><span>DataGrid.Columns</span><span>&gt;</span></li>
 <li><span>&lt;/</span><span>DataGrid</span><span>&gt;</span></li>
 </ol></div></div><br/>
Благодаря двухсторонней привязке, у меня есть возможность редактировать мой список задач. Ещё я добавил панель инструментов с одной кнопкой - для сохранения и обновления списка переходов.<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>&lt;</span><span>ToolBar</span><span> Grid.Row</span><span>=&quot;1&quot;&gt; </span></li>
 <li> <span>&lt;</span><span>Button</span><span> Command</span><span>=&quot;{</span><span>Binding</span><span> ApplyCommand}</span><span>&quot;&gt;</span></li>
 <li> <span>&lt;</span><span>Image</span><span> Source</span><span>=&quot;Images/apply.png&quot;</span><span> Height</span><span>=&quot;16&quot;/&gt;</span></li>
 <li> <span>&lt;/</span><span>Button</span><span>&gt; </span></li>
 <li><span>&lt;/</span><span>ToolBar</span><span>&gt;</span></li>
 </ol></div></div><br/>
Итак, теперь я могу редактировать мои задачи прямо в интерфейсе. Но я ещё не могу добавить их туда. Я решил использовать событие Drop главного окна, чтобы легко добавлять новые записи в мой список задач.<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>private</span> <span>void</span> WindowDrop(<span>object</span> sender, <span>DragEventArgs</span> e)</li>
 <li>{</li>
 <li> <span>if</span> (e.Data <span>is</span> <span>DataObject</span> &amp;&amp; ((<span>DataObject</span>)e.Data).ContainsFileDropList())</li>
 <li> {</li>
 <li> <span>foreach</span> (<span>string</span> filePath <span>in</span> ((<span>DataObject</span>)e.Data).GetFileDropList())</li>
 <li> {</li>
 <li> <span>if</span> (<span>File</span>.Exists(filePath))</li>
 <li> _model.Add(filePath);</li>
 <li> }</li>
 <li> }</li>
 <li>}</li>
 </ol></div></div><br/>
В итоге, я получил приложение, которое позволяет синхронизировать мои списки переходов между всеми компьютерами. Также я предусмотрел, что если приложения, которое я указал на первом ПК, на втором ПК нет или путь к нему другой, - то ссылка на него на втором ПК не появится. Вот скрины моих результатов:<br/>
<br/>
<div style="text-align: center"><!--noindex--><a href="http://1.bp.blogspot.com/-8-aYW4bYi-g/TxBKtWWpg1I/AAAAAAAAC8Q/dzpbhUQp46c/s1600/2.png" rel="nofollow" style="margin-left: 1em; margin-right: 1em"><img src="http://1.bp.blogspot.com/-8-aYW4bYi-g/TxBKtWWpg1I/AAAAAAAAC8Q/dzpbhUQp46c/s1600/2.png" border="0"/></a><!--/noindex--></div><div style="text-align: center"><!--noindex--><a href="http://2.bp.blogspot.com/-8MGScubW_6c/TxBMs8YckxI/AAAAAAAAC8o/Fq60Sb6ysVE/s1600/3.png" rel="nofollow" style="margin-left: 1em; margin-right: 1em"><img src="http://2.bp.blogspot.com/-8MGScubW_6c/TxBMs8YckxI/AAAAAAAAC8o/Fq60Sb6ysVE/s1600/3.png" border="0"/></a><!--/noindex--></div><div style="text-align: center"><!--noindex--><a href="http://4.bp.blogspot.com/-nLjTJcUpW8I/TxBm9lLf4RI/AAAAAAAAC80/xkErDEErgD4/s1600/4.png" rel="nofollow" style="margin-left: 1em; margin-right: 1em"><img src="http://4.bp.blogspot.com/-nLjTJcUpW8I/TxBm9lLf4RI/AAAAAAAAC80/xkErDEErgD4/s400/4.png" border="0"/></a><!--/noindex--></div><br/>
Теперь об ограничениях. Моя программа никак не работает с папками, она никак не работает с аргументами приложений, и вдобавок ей нужны именно *.exe файлы, ярлыки тоже никак не отработают. Меня все эти ограничения вполне устраивают, поэтому я ими не занимался. <br/>
<br/>
Я было хотел выложить код программы на кодеплекс, но, как оказалось (и что, собственно, очевидно), использовать списки переходов для быстрого запуска программ идея не новая. Просто той функциональности, что была нужна мне, я в других программах не нашел, да и пощупать возможности панели задач уже давно чесались руки. Поэтому я свои исходники публиковать не буду (к тому же, я почти весь код в статье написал), а просто приведу несколько программ, которые решают подобные задачи.<br/>
<ul><li><!--noindex--><a href="http://en.www.ali.dj/jumplist-launcher/" rel="nofollow">Jumplist-Launcher</a><!--/noindex--></li>
 <li><!--noindex--><a href="http://jumplaunch.codeplex.com/" rel="nofollow">JumpLaunch</a><!--/noindex--></li>
 <li><!--noindex--><a href="http://browserchooser.codeplex.com/" rel="nofollow">Browser Chooser</a><!--/noindex--></li>
 <li><!--noindex--><a href="http://www.addictivetips.com/windows-tips/create-and-categorize-jump-list-items-with-seven-jump-launcher/" rel="nofollow">Seven Jump</a><!--/noindex--></li>
 </ul>Ещё ссылки:<br/>
<ul><li><!--noindex--><a href="http://windows.microsoft.com/ru-RU/windows7/products/features/jump-lists" rel="nofollow">Общее описание списков переходов</a><!--/noindex--></li>
 <li><!--noindex--><a href="http://system-administrators.info/?p=3494" rel="nofollow">Windows 7: Как изменить количество элементов в Jump List</a><!--/noindex--></li>
 <li><!--noindex--><a href="http://msdn.microsoft.com/ru-ru/library/system.windows.shell.jumplist.aspx" rel="nofollow">JumpList MSDN</a><!--/noindex--></li>
 <li><!--noindex--><a href="http://habrahabr.ru/tag/windows 7 taskbar/" rel="nofollow">О панели задач на Хабре</a><!--/noindex--></li>
 </ul><br/>
На этом всё. Всем спасибо.<br/>
<br/>
<b>UPD.</b> Думаю, следует пояснить. В классе TaskViewModel команда StartCommand запускает приложение. Это я сделал только для того, чтобы у меня была возможность запустить приложение из моей программы. К списку переходов эта команда не имеет никакого отношения. Вся работа со списком переходов в классе MainViewModel<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li><span>///</span><span> Функция, перезаписывает список переходов.</span></li>
 <li><span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li><span>public</span> <span>void</span> Apply()</li>
 <li>{</li>
 <li> <span>// очистка существующего списка</span></li>
 <li> _jumpList.JumpItems.Clear();</li>
 <li>&#160;</li>
 <li> <span>// получаем JumpTask</span></li>
 <li> <span>var</span> jumpTasks =</li>
 <li> (<span>from</span> task <span>in</span> Tasks.Select(x=&gt;x.GetTask())</li>
 <li> <span>where</span> <span>File</span>.Exists(task.ApplicationPath)</li>
 <li> <span>orderby</span> task.Title, task.Category </li>
 <li> <span>select</span> <span>new</span> <span>JumpTask</span></li>
 <li> {</li>
 <li> Title = task.Title ?? <span>string</span>.Empty,</li>
 <li> Description = task.Description ?? <span>string</span>.Empty,</li>
 <li> ApplicationPath = task.ApplicationPath ?? <span>string</span>.Empty,</li>
 <li> IconResourcePath = task.ApplicationPath ?? <span>string</span>.Empty,</li>
 <li> WorkingDirectory = <span>Path</span>.GetDirectoryName(task.ApplicationPath),</li>
 <li> CustomCategory = task.Category ?? <span>string</span>.Empty,</li>
 <li> }).ToList();</li>
 <li> <span>// Шаманим с сортировкой. Этот код вообще не обязателен, просто мне нужен был список в определенном порядке</span></li>
 <li> jumpTasks.Reverse();</li>
 <li> <span>// добавляем все JumpTask в список jumpTasks</span></li>
 <li> jumpTasks.ForEach(_jumpList.JumpItems.Add);</li>
 <li> <span>// применяем изменения</span></li>
 <li> _jumpList.Apply();</li>
 <li> <span>// сохраняем список в файл</span></li>
 <li> Save();</li>
 <li>}</li>
 </ol></div></div><br/>
Весь остальной код относится к работе непосредственно самой программы. Список переходов же доступен и тогда, когда программа не запущена.<br/>
<br/>
</div><div><img src="https://blogger.googleusercontent.com/tracker/8897990838383834685-6941989845948170241?l=tym32167.blogspot.com" width="1px" height="1px" border="0"/></div>]]></description>
      <category><![CDATA[WPF]]></category>
      <category><![CDATA[.NET]]></category>
      <category><![CDATA[Windows 7 Taskbar]]></category>
      <category><![CDATA[C#]]></category>
      <guid>http://feedproxy.google.com/~r/tym32167/~3/yUfJt2fBy5w/blog-post.html</guid>
      <pubDate>Fri, 13 Jan 2012 17:39:00 UT</pubDate>
      <dc:creator><![CDATA[tym32167]]></dc:creator>
    </item>
    <item>
      <title><![CDATA[Открыта регистрация на TechEd Europe 2012, скидка 300 EUR до 31 марта]]></title>
      <link>http://microgeek.ru/blogs/conf/1718/</link>
      <description><![CDATA[<p><img src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-44-06-metablogapi/2604.teched_5F00_24385D2A.gif" alt="teched" title="teched" width="550px" height="116px" border="0"/></p> <p>С 26 по 29 июня 2012 года в Амстердаме пройдет крупнейшая европейская конференция Microsoft для ИТ-профессионалов, разработчиков и руководителей ИТ-департаментов. В ходе конференции посетители смогут посетить более 1000 сессий, докладов, лабораторных работ и других обучающих активностей по всему спектру программных решений Microsoft текущего и будущего поколений.</p> <p>Каждый, кто зарегистрируется на TechEd Europe 2012, получит бесплатно подписку TechNet с полным доступом ко всему спектру клиентского и серверного программного обеспечения Microsoft.</p> <p>Участники конференции, которые прибудут на день раньше 25 июня смогут посетить специальные <!--noindex--><a href="http://europe.msteched.com/PreCons" rel="nofollow">вступительные семинары</a><!--/noindex-->, на которых будет рассказано про технологии и продукты компании.</p> <p><!--noindex--><a href="https://register.europe.msteched.com/" rel="nofollow">Зарегистрируйтесь</a><!--/noindex--> на конференцию TechEd Europe 2012 до 31 марта и вы сможете получить скидку в €300. Больше информации вы можете получить на сайте конференции по адресу <!--noindex--><a href="http://europe.msteched.com/" rel="nofollow">europe.msteched.com</a><!--/noindex-->.</p> <p>Конференции серии TechEd Europe проходят на английском языке. Напомню, что в 2011 году в Москве состоялась крупнейшая технологическая конференция Microsoft в России – Tech∙Ed Russia 2011. Все доклады читались на русском либо переводились на русский синхронным переводом. За два дня работы более 2500 специалистов в области информационных технологий из разных регионов России и стран СНГ посетили 160 докладов в 15 треках с целью узнать об инструментах, технологиях и решениях Microsoft. На сайте конференции <!--noindex--><a href="http://www.msteched.ru/" rel="nofollow">http://www.msteched.ru</a><!--/noindex--> доступны видеозаписи всех докладов и материалов с мероприятия. </p>]]></description>
      <category><![CDATA[teched]]></category>
      <category><![CDATA[teched russia]]></category>
      <category><![CDATA[teched europe]]></category>
      <guid isPermaLink="false">urn:bitrix:blog:post:1718</guid>
      <pubDate>Thu, 12 Jan 2012 09:09:53 UT</pubDate>
      <dc:creator><![CDATA[Vladimir Yunev]]></dc:creator>
    </item>
    <item>
      <title><![CDATA[Опасности в автоматической привязке модели в ASP.NET MVC]]></title>
      <link>http://microgeek.ru/blogs/gaidar/1720/</link>
      <description><![CDATA[<p>В своем посте про безопасность сайтов в ASP.NET MVC я совершенно забыл про одну очень неприятную атаку, применимую к действиям контроллеров, использующим автоматическую привязку модели и UpdateModel/TryUpdateModel.</p> <p>Представьте себе ситуацию, что на сайте добавляются комментарии, которые обязательно должны проходить модерацию, поэтому у них есть свойство <em>IsApproved</em>, по умолчанию в базе данных заданное как <em>false</em>. Например, модель выглядит как:</p> <pre>public class Comment {
    int CommentId {get; set;};
    // еще много разных полей …
    string Text {get; set;};
    string Author {get; set;};
    bool IsApproved {get; set;};
}
</pre> <p>Представим себе, что при отправке формы пользователь заполняет поле textarea с идентификатором Text и input поле с идентификатором Author, а на стороне сервера действие, сохраняющее комментарий в базу данных выглядит как:</p> <pre>[HttpPost]
public ActionResult SaveComment( Comment obj) {
    // тут всякий разный код
    UpdateModel( obj );
    // тут еще какой-то разный код
}
</pre> <p>В этом случае нехороший пользователь может эмулировать POST обращение на сервер и передать пару значений <em>IsApproved = true</em>, чтобы автоматически показать сообщение без модерации. В этом сценарии, может быть, это не так страшно – комментарий можно удалить, однако похожий сценарий может быть применим к каким-то более важным бизнес-данным, поэтому такого допускать нельзя.</p> <p>Есть три основных подхода, позволяющие избежать подобной проблемы.</p> <p><strong>Минимум кода – привязывать только нужные поля.</strong></p> <p>Для этого можно передавать параметры в метод UpdateModel():</p> <pre>UpdateModel ( obj, <span>&quot;</span>Comment<span>&quot;</span>, new string { <span>&quot;</span>Text<span>&quot;</span>, <span>&quot;</span>Author<span>&quot;</span> };</pre> <p>Еще один вариант, пометить аргумент действия атрибутом Bind:</p> <pre>[HttpPost]
public ActionResult SaveComment( 
                 [Bind(Include = &quot;Text, Author&quot;)] Comment obj) {
    // … тут всякий разный код
    UpdateModel( obj );
    // тут еще какой-то разный код
}
</pre> <p>Атрибут Bind можно использовать и в варианте [Bind(Exclude = “”)], указывая список полей, привязку которых не следует осуществлять. Однако метод с указанием только нужных полей оказывается надежнее при дальнейших модификациях модели – свойства остаются защищены от изменений, несмотря на то, что добавляются новые свойства в модели.</p> <p><strong>Чуть больше кода – использовать промежуточные модели.</strong></p> <p>Такой подход подразумевает создание отдельных классов моделей для использования на стороне представлений, часто называемых ViewModel. Эти модели являются упрощенными вариантами полноценных моделей данных и предоставляют только свойства, которые необходимы обработки получаемых данных. Например, для комментариев такая модель может выглядеть так:</p> <pre>public class CommentViewModel{
    string Text {get; set;};
    string Author {get; set;}
}
</pre> <p>В этом случае при обновлении базы данных придется конструировать новые объекты Comment, присваивать значения полей объектов типа CommentViewModel объектам типа Comment и сохранять уже объекты Comment в базу данных.</p> <p><strong>Совсем много кода – привязывать поля вручную</strong></p> <p>Самый гибкий, но и самый кропотливый в реализации способ – отказаться от использования методов UpdateModel и TryUpdateModel и проводить валидацию всех полей и конструирование нужных объектов самостоятельно. Этот метод оправдан когда для передаваемых данных необходимо выполнять сложные проверки и конструировать не один объект, а набор объектов со сложной логикой связи между ними. Кроме того, этот метод любят те, кто боится доверять привязку данных MVC Framework.</p>]]></description>
      <category><![CDATA[development]]></category>
      <category><![CDATA[security]]></category>
      <guid>http://radiag.ru/post/15716076003</guid>
      <pubDate>Thu, 12 Jan 2012 08:10:05 UT</pubDate>
      <dc:creator><![CDATA[gaidar]]></dc:creator>
    </item>
    <item>
      <title><![CDATA[Microsoft обеспечит "Лабораторию Касперского" новейшим ПО]]></title>
      <link>http://microgeek.ru/blogs/partners/1701/</link>
      <description><![CDATA[<p><i>Соглашение с &#171;Лабораторией Касперского&#187; стало одной из самых крупных международных сделок </i><i>Microsoft</i><i> в России и проиллюстрировало наиболее значимые тенденции российского рынка информационных технологий. </i></p> <p><b>Москва, 11 января 2012 года. </b>— Компания Microsoft объявила о подписании с &#171;Лабораторией Касперского&#187; договора на поставку новейших программных продуктов и решений Microsoft. Это одна из крупнейших международных сделок Microsoft в России, условия которой предполагают поставку решений в зарубежные представительства &#171;Лаборатории Касперского&#187; в Западной и Восточной Европе, Северной и Южной Америках, на Ближнем Востоке и в Африке, в Азиатско-Тихоокеанском регионе. </p> <p>Данное соглашение призвано обеспечить стандартизацию глобальной ИТ-инфраструктуры &#171;Лаборатории Касперского&#187;. Оно предполагает поставку нового программного обеспечения для более чем 2100 компьютеров, развертывание единой инфраструктуры на более чем 400 серверах, а также создание частного облака в дата-центрах компании.</p> <p>&#171;Соглашение включает в себя самую полную линейку решений Microsoft, которые помогут &#171;Лаборатории Касперского&#187; решить бизнес-задачи и обеспечить стандартизацию ИТ-инфраструктуры. Мы уверены, что данное соглашение – это залог успешного сотрудничества наших компаний как сегодня, так и в будущем&#187;, – прокомментировал событие Николай Прянишников, президент Microsoft в России.</p> <p>&#171;Мы используем технологии Microsoft уже много лет и довольны результатами, – говорит Андрей Тихонов, директор по информационным технологиям &#171;Лаборатории Касперского&#187;. – Подписанное соглашение – это следующий шаг на пути повышения эффективности нашей компании с помощью новейших технологий. Оно позволит унифицировать наше программное обеспечение и ИТ-инфраструктуру по всему миру, применяя оптимально подходящие решения&#187;.</p> <p>Соглашение с &#171;Лабораторией Касперского&#187; иллюстрирует тенденции, которые сегодня наблюдаются на рынке информационных технологий России. Среди них:</p> <p><b>Рост спроса на решения по управлению бизнес-процессами.</b> &#171;Лаборатория Касперского&#187; успешно внедрила систему управления взаимоотношениями с клиентами Microsoft Dynamics CRM, а также применяет систему управления проектами Enterprise Project Management 2010.</p> <p><b>Повышение интереса компаний к решениям для объединенных коммуникаций и совместной работы. </b>&#171;Лаборатория Касперского&#187; выбрала для обеспечения эффективной совместной работы сотрудников почтовое решение Exchange 2010 и систему корпоративной аудио- и видеоконференцсвязи Lync 2010.</p> <p><b>Рост спроса на технологии бизнес-аналитики.</b> В компании &#171;Лаборатория Касперского&#187; внедрена система бизнес-аналитики на базе Microsoft SQL Server 2008, а также создан ряд порталов на базе технологии SharePoint Server 2010. Кроме того, для осуществления поиска на порталах будет внедрено корпоративное решение FAST.</p> <p><b>Повышение качества управления дата-центром.</b> Так, в &#171;Лаборатории Касперского&#187; внедрены решения для управления инфраструктурой Microsoft System Center.</p> <p><b>Переход к облачной инфраструктуре</b>. В компании &#171;Лаборатория Касперского&#187; построено частное облако на базе Windows Server 2008 R2 с гипервизором Hyper-V и средствами управления Microsoft Systems Center.</p> <p>Защита периметра сети осуществляется с помощью Forefront TMG 2010. В планы на ближайшее будущее входит стандартизация рабочих мест на базе расширенного пакета лицензий Enterprise Desktop (включает Windows 7, Office 2010 и др.), а также применение популярной платформы для разработки ПО Visual Studio 2010 и Team Foundation Server 2010. Кроме того, будет расширена подписка TechNet Professionals.</p> <p>Сотрудничество Microsoft и &#171;Лаборатории Касперского&#187; продолжится в рамках распространения проектов, внедренных в головном офисе, на все страны присутствия компании, а также при создании единой управляемой из России платформы, опирающейся на передовые технологии Microsoft.</p> <p><b>О &#171;Лаборатории Касперского&#187;</b></p> <p>&#171;Лаборатория Касперского&#187; — крупнейший в Европе производитель систем защиты от вредоносного и нежелательного ПО, хакерских атак и спама. Компания входит в четверку ведущих мировых производителей программных решений для обеспечения информационной безопасности. По итогам 2010 года, выручка компании выросла на 38%, превысив 500 млн долларов США. В &#171;Лаборатории Касперского&#187; работают более 2300 высококвалифицированных специалистов. Продукты компании надежно защищают компьютеры и мобильные устройства более 300 млн пользователей во всем мире, технологии используются в продуктах крупнейших мировых поставщиков программных и аппаратных решений. Более подробную информацию можно получить на сайте <!--noindex--><a href="http://www.kaspersky.ru/" rel="nofollow">www.kaspersky.ru</a><!--/noindex-->.</p> ]]></description>
      <category><![CDATA[microsoft]]></category>
      <category><![CDATA[лаборатория касперского]]></category>
      <guid isPermaLink="false">urn:bitrix:blog:post:1701</guid>
      <pubDate>Wed, 11 Jan 2012 11:11:05 UT</pubDate>
      <dc:creator><![CDATA[Vladimir Yunev]]></dc:creator>
    </item>
    <item>
      <title><![CDATA[Безопасность веб-сайтов ASP.NET MVC]]></title>
      <link>http://microgeek.ru/blogs/gaidar/1719/</link>
      <description><![CDATA[<p>&#171;Ломать – не строить&#187;, гласит народная мудрость. Чтобы создать полезное для пользователей веб-приложение, приходится прикладывать много усилий, придумывать нужную функциональность и реализовывать ее. Чтобы сломать веб-приложение, существует набор стандартных методик, рассчитанных на то, что разработчик веб-приложения не подумал или поленился защитить свое веб-приложение от определенного типа атак.</p> <p>Сторонники &#171;хакерских игр&#187; могут возмутиться, что взлом веб-сайта тоже сложная и кропотливая работа. Так-то оно, может быть, и так, однако по своей сути взлом в подавляющем большинстве случаев основан на стандартных подходах и оставленных разработчиком лазейках. В конечном итоге изобрести колесо сложнее, чем придумать, как проколоть его гвоздем, хотя последнее тоже может быть увлекательной задачей.</p> <p>Таким образом, у нападающего на сайт взломщика есть набор практик и инструментов, позволяющих пробовать стандартные подходы для взлома веб-сайта, поэтому веб-разработчик, создающий веб-приложение, должен также иметь собственный список задач по обеспечению безопасности веб-приложения. Основные советы я привожу в этой небольшой статье. Позднее я напишу более подробно о нескольких самых распространенных атаках.</p> <h3>Базовые советы по обеспечению безопасности веб-приложений</h3> <p><strong>1. Валидация пользовательского ввода</strong></p> <p>При получении любых данных от пользователя, обязательно должна осуществляться проверка на размер и формат данных, применение ограничений по допустимым значениям, предусмотренных бизнес логикой и проверка данных на безопасность. В случае, если с данными что-то не так, то существует два стандартных подхода – либо вернуть их пользователю с ошибкой, либо попытаться их &#171;очистить&#187;. Второй путь часто выбирают для облегчения жизни пользователя, например при вводе даты или времени в неверном формате, однако этот путь опасен не только с точки зрения возможных ошибок в коде, &#171;очищающем&#187; данные, так и с точки зрения нарушения логики приложения.</p> <p>Основная рекомендация – отклонять некорректные данные и предлагать пользователю ввести данные в правильном формате.</p> <p>Сложности возникают в классической задаче: ввод HTML тегов для оформления публикуемых на сайте текстов. Если пытаться вырезать недопустимые теги, существует большая вероятность, что злоумышленник придумает способ, как обойти &#171;вырезалку&#187; теги. Если же отклонять введенный текст, то пользователь может быть очень расстроен тем, что не понимает, из-за чего его текст был отклонен и где в нем недопустимый тег. Здесь на помощь приходит следующий совет.</p> <p>Для часто используемых проверок имеет смысл создать вспомогательный класс, содержащий методы для проверки вводимых данных, тогда код может выглядеть как-то так:</p> <pre>public ActionResult ProcessData ( DataObject data )
{
    // Валидация
    if (! SomeValidationLogic.ValidateSomeData (data.DataField) )
        ModelState.AddModelError (&quot;DataField&quot;, &quot;DataField is invalid&quot;);
    // ... там дальше много кода
}
</pre> <p>В свое время для MVC Framework 1.0 создавались различные библиотеки валидации вроде <!--noindex--><a href="http://mvcvalidatortoolkit.codeplex.com/" rel="nofollow">Validator Toolkit for ASP.NET MVC</a><!--/noindex--> или <!--noindex--><a href="http://xval.codeplex.com/" rel="nofollow">xVal </a><!--/noindex-->– можно посмотреть на их устройство для общего развития. Из неплохих современных фреймворков для валидации данных существует <!--noindex--><a href="http://fluentvalidation.codeplex.com/" rel="nofollow">FluentValidation</a><!--/noindex-->.</p> <p>В случае если используются механизмы валидации данных на клиенте, они должны быть продублированы на сервере. Злоумышленнику ничего не стоит модифицировать клиентские страницы либо эмулировать передачу данных со страниц на сервер. Относитесь к коду клиентской валидации как к возможности сэкономить время пользователя при подготовке данных в нужном формате, а не как к дополнительной степени защиты прилжения.</p> <p><strong>2. Форматирование вывода пользовательских данных</strong></p> <p>При публикации данных, так или иначе пришедших из внешних источников, на страницах вашего веб-приложения, обязательно нужно исключать возможность атак, подразумевающих внедрение вредоносного кода на страницы. Да и просто &#171;кривая&#187; разметка может испортить внешний вид страниц и отпугнуть пользователей вашего сайта, поэтому корректное форматирование текстов всегда является хорошим выходом.</p> <p>Для того чтобы избежать проблем с выводом разметки, там где вы ее не ожидаете, используйте метод Html.Encode(). Если же нужно допустить вывод некоторых тегов, то вы можете воспользоваться методами AntiXss.HtmlEncode() и AntiXss.HtmlAttributeEncode(), реализованном в библиотеке AniXSS, входящей в проект <!--noindex--><a href="http://wpl.codeplex.com/" rel="nofollow">Microsoft Web Protection Library</a><!--/noindex-->. В библиотеке AniXSS также доступен метод AntiXss.GetSafeHtmlFragment(), позволяющий выводить &#171;безопасные&#187; теги, вырезая &#171;опасные&#187; и корректно форматируя разметку.</p> <p>Библиотеку AntiXss можно зарегистрировать в для использования по умолчанию для кодирования HTML разметки, об этом написано пошаговое руководство в <!--noindex--><a href="http://haacked.com/archive/2010/04/06/using-antixss-as-the-default-encoder-for-asp-net.aspx" rel="nofollow">блоге у Фила Хаака</a><!--/noindex-->.</p> <p><strong>3. Корректное использование метода POST и защищенного протокола HTTPS</strong></p> <p>Данные, которые приложение ожидает получить методом POST, должны приходить методом POST, для этого достаточно использовать атрибут HttpPost на действиях контроллеров, ожидающих данные методом POST – таким образом можно защититься от атак, заставляющих добропорядочных пользователей переходить по ссылкам, передающим данные методом GET.</p> <p>Хорошая практика использовать метод POST при выполнении важных действий, таких как удаление или изменение данных, поскольку злоумышленник легко может подставить пользователю ссылку вроде /somecontroller/delete/1 с другого сайта, заставив авторизованного ранее на вашем сайте пользователя, выполнить не всегда полезное действие.</p> <p>Для данных, имеющих большую ценность, например, таких как персональные данные и данные о кредитных картах, стоит использовать безопасный протокол передачи данных HTTPS. При этом, <!--noindex--><a href="http://radiag.ru/post/14660328307/http-and-https-forms" rel="nofollow">сами формы, запрашивающие данные, должны быть отправлены по HTTPS</a><!--/noindex--> пользователю, чтобы не давать злоумышленнику возможностей украсть или модифицировать данные перед отправкой на ваш сервер. Здесь на помощь приходит атрибут RequireHttps на соответствующих действиях контроллеров, требующий передачи данных по протоколу HTTPS.</p> <p>В случаях, когда пользователя необходимо перенаправить на ту же форму по протоколу HTTPS, можно реализовать собственный фильтр, который будет автоматически осуществлять перенаправление для помеченных им действий.</p> <pre>public class UseHttps : ActionFilterAttribute 
{ 
  public override void OnActionExecuting(
                             ActionExecutingContext filterContext) { 

      if ( !filterContext.HttpContext.Request.IsSecureConnection) { 
          filterContext.Result =  
            new RedirectResult(
              filterContext.HttpContext.Request.Url.ToString().Replace
                                                  (&quot;http:&quot;, &quot;https:&quot;));

               filterContext.Result.ExecuteResult(filterContext); 
      } 
      base.OnActionExecuting(filterContext); 
   } 
}
</pre> <p><strong>4. Корректная обработка ошибок и исключений</strong></p> <p>Ошибки и исключения в веб-приложениях случаются. В случае обращения по несуществующим адресам, либо при вызове действий контроллеров с идентификаторами несуществующих записей или некорректными идентификаторами данных сообщения об ошибках должны быть информативны для пользователя, однако не предоставлять информации о внутреннем устройстве веб-приложения. Аналогично и в случае возникновения исключений в обрабатывающем запросе коде или коде нижележащих слоев приложения. Достигается это с помощью <!--noindex--><a href="http://msdn.microsoft.com/ru-ru/library/h0hfz6fc.aspx" rel="nofollow">включения Custom Errors в web.config</a><!--/noindex-->.</p> <p>Отдельно стоит обратить внимание на поведение веб-приложения при попытке неудачной загрузки файла: проверить корректность сообщений об ошибках при недостатке свободного места во временной директории на сервере, а также при загрузке чрезмерно большого файла (таймаут, ограничение на размер запроса на уровне IIS). Злоумышленник не должен меть возможность получать информацию о структуре файловой системы сервера.</p> <p><strong>5. Контроль прав доступа пользователей</strong></p> <p>При осуществлении пользователем действий, требующих определенных привилегий, необходимо проверять наличие у пользователя этих привилегий (роли, прав доступа к данным) при каждом обращении. Недостаточно проверять права доступа только при отображении основного действия со списком команд и в дальнейшем проверять лишь наличие авторизации пользователя. Совет достаточно простой, однако о нем легко забыть, пользуясь атрибутом [Authorize]. Следует проверить, что на действиях, требующих принадлежности к определенным ролям, указаны эти роли, например [Authorize(Roles = “Admin, Moderator”)].</p> <p>В случаях, когда необходима более сложная логика авторизации, например на основании свойств объекта данных, может быть удобно создать собственный фильтр для авторизации. Например, если в базе данных для каждого типа данных прописан список пользователей имеющих доступ на редактирование данных, то в действии Edit может быть использован собственный фильтр AuthorizeItem, которые проверяет наличие у пользователя прав на редактирование данного конкретного объекта.</p> <pre>public class AuthorizeItemAttribute: FilterAttribute, IAuthorizationFilter 
{ 
 
    public void OnAuthorization(AuthorizationContext filterContext) 
    { 
        //...
        // здесь идет код логики авторизации
        // доступа к данным на основании свойств
        // данных
        // ...
}
</pre> <p>Частая ошибка, которую делают разработчики в таких случаях – скрывают ссылки на редактирование объектов, не защищая сам метод, позволяющий редактировать объект.</p> <p>Другой вариант решения – проверять авторизацию пользователя на уровне слоя доступа к данным, либо, для большей надежности, объединить оба этих подхода.</p> <p><strong>Почему эти советы особенно важны в контексте использования ASP.NET MVC?</strong></p> <p>В технологии ASP.NET WebForms часть из описанных выше проблем безопасности была решена за разработчика автоматически, например, WebForms брали на себя кодирование выводимого на экран текста (если не использовался Response.Write(), конечно), валидацию ViewState, валидацию параметров запросов и защиту от инъекций через валидацию механизма клиентских событий. Разумеется, для полной защиты от разных типов атак, разработчику требовалось соблюдать базовые принципы безопасности, однако во многом платформа WebForms брала заботы о безопасности на себя.</p> <p>Разумеется, дополнительная защита, как и многие другие приятные полезности в WebForms, снижала гибкость решения и повышала нагрузку на систему, собственно, почему некоторые разработчики и выбирают ASP.NET MVC в погоне за большей гибкостью и большими возможностями расширения веб-приложений. В связи с этим, отказываясь от дополнительных возможностей в угоду гибкости, нужно быть готовым приложить больше усилий к тому, чтобы обезопасить веб-приложение.</p> <p><strong>Зачем ломают веб-сайты?</strong></p> <p>Часто веб-разработчики пренебрегают угрозой, считая свой сайт защищенным методом &#171;неуловимого Джо, который совсем никому не нужен&#187;. Однако, современные хакеры в большинстве своем не веселые добряки из девяностых годов, ломающие сайты только ради взлома или дефейса (публикации ругательных надписей и забавных картинок на главных страницах сайтов). Современным хакером движет жажда наживы и его цели вовсе не так прозрачны, как &#171;просто уронить сайт&#187;. Взломщики охотятся за базами персональной пользовательской информации, списками рассылок, возможностями осуществлять спам-рассылки от лица вашего сайта, данными учетных записей сервисов в социальных сетях, если они как-то представлены на вашем сайте. Помимо этого, цель взломщиков может быть еще более хитрой – получение информации о друзьях пользователей и их предпочтениях в музыке, кино, книгах, с целью дальнейших рассылок с возможностью &#171;втираться&#187; в доверие пользователей, представляясь их друзьями, что-то знающими об их вкусах.</p> <p>Цели злоумышленников могут быть разные, поэтому главный принцип защиты – не дать им получить ничего, что сайт не позволяет получить анонимным пользователям. Любая информация, кажущаяся не ценной для вас, может быть ценной для ваших пользователей и может быть эксплуатирована злоумышленниками.</p> <p><strong>Как жить дальше?</strong></p> <p>Помнить об основных принципах безопасности веб-приложений и жить хорошо. В ближайшие дни я опубликую еще несколько небольших статей про самые неприятные атаки на веб-приложения и борьбу с ними.</p> <p><em>Пожелания и комментарии по статье с радостью принимаются. Безопасность – тема сложная и всеобъемлющая, поэтому буду рад, если вы поделитесь советами в комментариях к этой статье.</em></p>]]></description>
      <category><![CDATA[development]]></category>
      <category><![CDATA[security]]></category>
      <guid>http://radiag.ru/post/15663930162</guid>
      <pubDate>Wed, 11 Jan 2012 08:00:00 UT</pubDate>
      <dc:creator><![CDATA[gaidar]]></dc:creator>
    </item>
    <item>
      <title><![CDATA[Новый курс по веб-разработке для начинающих на русском MSDN]]></title>
      <link>http://microgeek.ru/blogs/aspnet/1700/</link>
      <description><![CDATA[<p><img src="http://upload.wikimedia.org/wikipedia/en/a/ae/MSDN_Logo.png" border="0"/></p> <p>На <!--noindex--><a href="http://msdn.microsoft.com/ru-ru/asp.net/default.aspx" rel="nofollow">русском MSDN</a><!--/noindex--> опубликован обновленный курс по веб-разработке для начинающих c помощью ASP.NET и бесплатной среды разработки <!--noindex--><a href="http://www.microsoft.com/web/webmatrix/" rel="nofollow">WebMatrix</a><!--/noindex-->. Новый курс состоит из <!--noindex--><a href="http://msdn.microsoft.com/ru-ru/asp.net/hh552772" rel="nofollow">16 статей</a><!--/noindex--> на русском языке, которые дадут достаточно знаний для создания своих первых сайтов и получения навыков веб-разработки.</p> <p>Содержание курса:</p> <ul> <li><!--noindex--><a href="http://msdn.microsoft.com/ru-ru/asp.net/hh552772" rel="nofollow">Глава 1. Начало работы с WebMatrix и веб-страницами ASP.NET</a><!--/noindex--> </li>
 <li><!--noindex--><a href="http://msdn.microsoft.com/ru-ru/asp.net/hh535202" rel="nofollow">Глава 2. Использование кода веб-страниц ASP.NET</a><!--/noindex--> </li>
 <li><!--noindex--><a href="http://msdn.microsoft.com/ru-ru/asp.net/hh535203" rel="nofollow">Глава 3. Более сложный пример на ASP.NET</a><!--/noindex--> </li>
 <li><!--noindex--><a href="http://msdn.microsoft.com/ru-ru/asp.net/hh535204" rel="nofollow">Глава 4. Знакомство с синтаксисом Razor. Рекомендации по программированию</a><!--/noindex--> </li>
 <li><!--noindex--><a href="http://msdn.microsoft.com/ru-ru/asp.net/hh535346" rel="nofollow">Глава 5. Знакомство с синтаксисом Razor, серверный код и ASP.NET</a><!--/noindex--> </li>
 <li><!--noindex--><a href="http://msdn.microsoft.com/ru-ru/asp.net/hh535382" rel="nofollow">Глава 6. Знакомство с синтаксисом Razor. Обработка ошибок</a><!--/noindex--> </li>
 <li><!--noindex--><a href="http://msdn.microsoft.com/ru-ru/asp.net/hh535407" rel="nofollow">Глава 7. Работа с формами</a><!--/noindex--> </li>
 <li><!--noindex--><a href="http://msdn.microsoft.com/ru-ru/asp.net/hh535422" rel="nofollow">Глава 8. Работа с данными</a><!--/noindex--> </li>
 <li><!--noindex--><a href="http://msdn.microsoft.com/ru-ru/asp.net/hh563480" rel="nofollow">Глава 9. Отображение данных</a><!--/noindex--> </li>
 <li><!--noindex--><a href="http://msdn.microsoft.com/ru-ru/asp.net/hh563481" rel="nofollow">Глава 10. Работа с изображениями</a><!--/noindex--> </li>
 <li><!--noindex--><a href="http://msdn.microsoft.com/ru-ru/asp.net/hh641417" rel="nofollow">Глава 11. Работа с видео</a><!--/noindex--> </li>
 <li><!--noindex--><a href="http://msdn.microsoft.com/ru-ru/asp.net/hh694553" rel="nofollow">Глава 12. Кэширование и оптимизация производительности</a><!--/noindex--> </li>
 <li><!--noindex--><a href="http://msdn.microsoft.com/ru-ru/asp.net/hh694596" rel="nofollow">Глава 13. Анализ трафика и посещаемости</a><!--/noindex--> </li>
 <li><!--noindex--><a href="http://msdn.microsoft.com/ru-ru/asp.net/hh694618" rel="nofollow">Глава 14. Оптимизация веб-страниц для поисковых систем</a><!--/noindex--> </li>
 <li><!--noindex--><a href="http://msdn.microsoft.com/ru-ru/asp.net/hh674704" rel="nofollow">Глава 15. Использование пакетного менеджера</a><!--/noindex--> </li>
 <li><!--noindex--><a href="http://msdn.microsoft.com/ru-ru/asp.net/hh694633" rel="nofollow">Часть 16. Разработка ASP.NET WebPages и Razor в Visual Studio</a><!--/noindex--> </li>
 </ul> <p>Кроме того, для PHP и ASP.NET разработчиков на русском MSDN опубликованы дополнительные материалы по профессиональному использованию WebMatrix в том числе для работы с популярными CMS:</p> <ul> <li><!--noindex--><a href="http://msdn.microsoft.com/ru-ru/asp.net/hh343283" rel="nofollow">Быстрая установка и публикация на сервер проекта WordPress с помощью WebMatrix</a><!--/noindex--> </li>
 <li><!--noindex--><a href="http://msdn.microsoft.com/ru-ru/asp.net/hh420775" rel="nofollow">Быстрая установка и публикация на сервер CRM-проекта на базе SugarCRM</a><!--/noindex--> </li>
 <li><!--noindex--><a href="http://msdn.microsoft.com/ru-ru/asp.net/hh490327" rel="nofollow">Быстрая установка и публикация на сервер с помощью WebMatrix проекта на базе Drupal</a><!--/noindex--> </li>
 <li><!--noindex--><a href="http://msdn.microsoft.com/ru-ru/asp.net/hh707894" rel="nofollow">Быстрая установка и публикация на сервер проекта на базе Joomla с помощью WebMatrix</a><!--/noindex--> </li>
 <li><!--noindex--><a href="http://msdn.microsoft.com/ru-ru/asp.net/hh443651" rel="nofollow">Видео: быстрое создание сайта сообщества с помощью WebMatrix и .NET Forge CMS</a><!--/noindex--> </li>
 <li><!--noindex--><a href="http://msdn.microsoft.com/ru-ru/asp.net/hh443652" rel="nofollow">Видео: Быстрая загрузка, установка, настройка и публикация WordPress с помощью WebMatrix</a><!--/noindex--> </li>
 <li><!--noindex--><a href="http://msdn.microsoft.com/ru-ru/asp.net/hh530993" rel="nofollow">Видео: быстрая установка и настройка проекта на базе SugarCRM с помощью WebMatrix</a><!--/noindex--> </li>
 <li><!--noindex--><a href="http://msdn.microsoft.com/ru-ru/asp.net/hh530998" rel="nofollow">Видео: быстрая установка и настройка проекта на базе Drupal с помощью WebMatrix</a><!--/noindex--> </li>
 <li><!--noindex--><a href="http://msdn.microsoft.com/ru-ru/asp.net/hh705278" rel="nofollow">Отладчик страниц для WebMatrix</a><!--/noindex--> </li>
 <li><!--noindex--><a href="http://msdn.microsoft.com/ru-ru/asp.net/gg430293" rel="nofollow">Краткий справочник по API ASP.NET</a><!--/noindex--> </li>
 <li><!--noindex--><a href="http://msdn.microsoft.com/ru-ru/asp.net/gg430295" rel="nofollow">Применение VisualBasic на веб-страницах ASP.NET</a><!--/noindex--> </li>
 <li><!--noindex--><a href="http://msdn.microsoft.com/ru-ru/asp.net/hh335107" rel="nofollow">WebMatrix: работа с пакетом определения мобильных клиентов от 51Degrees.mobi</a><!--/noindex--></li>
 </ul>]]></description>
      <category><![CDATA[.net]]></category>
      <category><![CDATA[cms]]></category>
      <category><![CDATA[asp.net]]></category>
      <category><![CDATA[webmatrix]]></category>
      <guid isPermaLink="false">urn:bitrix:blog:post:1700</guid>
      <pubDate>Wed, 11 Jan 2012 07:34:45 UT</pubDate>
      <dc:creator><![CDATA[Vladimir Yunev]]></dc:creator>
    </item>
    <item>
      <title><![CDATA[Calculon доступен для загрузки]]></title>
      <link>http://microgeek.ru/blogs/tym32167/1717/</link>
      <description><![CDATA[<div style="text-align: left">Добрый день. Вчера получил письмо из Майкрософта<br/>
<div style="text-align: center"><!--noindex--><a href="http://4.bp.blogspot.com/-HmoEbYmxUio/TwgrXZ5wqcI/AAAAAAAAC7M/PHrASeDpGZ0/s1600/1.PNG" rel="nofollow" style="margin-left: 1em; margin-right: 1em"><img src="http://4.bp.blogspot.com/-HmoEbYmxUio/TwgrXZ5wqcI/AAAAAAAAC7M/PHrASeDpGZ0/s640/1.PNG" width="640px" height="460px" border="0"/></a><!--/noindex--></div>А с сегодняшнего дня Calculon <!--noindex--><a href="http://www.windowsphone.com/ru-RU/apps/78304b62-c22c-471d-adbb-b30a61c8ebca" rel="nofollow">доступен для загрузки</a><!--/noindex--> в Marketplace! Напмню, что Calculon - бесплатное приложение-калькулятор, процесс создания которого я <!--noindex--><a href="http://tym32167.blogspot.com/2012/01/silverlight-windows-phone-7.html" rel="nofollow">описывал</a><!--/noindex--> в блоге и исходный код которого выложил на <!--noindex--><a href="http://calculon.codeplex.com/" rel="nofollow">кодеплекс</a><!--/noindex-->.<br/>
<br/>
</div><div><img src="https://blogger.googleusercontent.com/tracker/8897990838383834685-7588480118029392048?l=tym32167.blogspot.com" width="1px" height="1px" border="0"/></div>]]></description>
      <category><![CDATA[Windows Phone]]></category>
      <category><![CDATA[.NET]]></category>
      <category><![CDATA[C#]]></category>
      <guid>http://tym32167.blogspot.com/2012/01/calculon.html</guid>
      <pubDate>Sat, 07 Jan 2012 11:46:00 UT</pubDate>
      <dc:creator><![CDATA[tym32167]]></dc:creator>
    </item>
    <item>
      <title><![CDATA[Calculon доступен для загрузки]]></title>
      <link>http://microgeek.ru/blogs/tym32167/1723/</link>
      <description><![CDATA[<div style="text-align: left">Добрый день. Вчера получил письмо из Майкрософта<br/>
<div style="text-align: center"><!--noindex--><a href="http://4.bp.blogspot.com/-HmoEbYmxUio/TwgrXZ5wqcI/AAAAAAAAC7M/PHrASeDpGZ0/s1600/1.PNG" rel="nofollow" style="margin-left: 1em; margin-right: 1em"><img src="http://4.bp.blogspot.com/-HmoEbYmxUio/TwgrXZ5wqcI/AAAAAAAAC7M/PHrASeDpGZ0/s640/1.PNG" width="640px" height="460px" border="0"/></a><!--/noindex--></div>А с сегодняшнего дня Calculon <!--noindex--><a href="http://www.windowsphone.com/ru-RU/apps/78304b62-c22c-471d-adbb-b30a61c8ebca" rel="nofollow">доступен для загрузки</a><!--/noindex--> в Marketplace! Напмню, что Calculon - бесплатное приложение-калькулятор, процесс создания которого я <!--noindex--><a href="http://tym32167.blogspot.com/2012/01/silverlight-windows-phone-7.html" rel="nofollow">описывал</a><!--/noindex--> в блоге и исходный код которого выложил на <!--noindex--><a href="http://calculon.codeplex.com/" rel="nofollow">кодеплекс</a><!--/noindex-->.<br/>
<br/>
</div><div><img src="https://blogger.googleusercontent.com/tracker/8897990838383834685-7588480118029392048?l=tym32167.blogspot.com" width="1px" height="1px" border="0"/></div>]]></description>
      <category><![CDATA[Windows Phone]]></category>
      <category><![CDATA[.NET]]></category>
      <category><![CDATA[C#]]></category>
      <guid>http://feedproxy.google.com/~r/tym32167/~3/K8wstfAUVu4/calculon.html</guid>
      <pubDate>Sat, 07 Jan 2012 11:46:00 UT</pubDate>
      <dc:creator><![CDATA[tym32167]]></dc:creator>
    </item>
    <item>
      <title><![CDATA[Готовим стратегию в реальном времени (RTS) в домашних условиях]]></title>
      <link>http://microgeek.ru/blogs/tym32167/1716/</link>
      <description><![CDATA[<div style="text-align: left">Эх, давно хотел попробовать написать какую-нибудь игру. К тому же уже был опыт работы с 3D графикой, как с DirectX, так и с OpenGL, но всё некогда, некогда. Тогда я решил воспользоваться одним из готовых 3D движков, и поковырять его. Что из этого вышло...<br/>
<a name="more" rel="nofollow"></a><br/>
В общем, на хабре как то проскочила <!--noindex--><a href="http://habrahabr.ru/blogs/gdev/134937/" rel="nofollow">статья</a><!--/noindex--> о отечественном движке <!--noindex--><a href="http://www.neoaxis.com/ru" rel="nofollow">NeoAxis</a><!--/noindex-->. Давно его скачал, но вот только руки дошли поглядеть, что внутри. <br/>
Итак, движок, насколько я помню, основан на <!--noindex--><a href="http://www.ogre3d.org/" rel="nofollow">Ogre 3D</a><!--/noindex-->, работа с графикой написана на неуправляемом C++, вокруг которого наворотили обёрток и дали нам. простым смертным, писать под него логику на любом .NET языке. Имеет несколько вариантов <!--noindex--><a href="http://www.neoaxis.com/ru/neoaxis/licensing" rel="nofollow">лицензий</a><!--/noindex-->, в том числе и некоммерческую, которые отличаются ценой и возможностями. Также на <!--noindex--><a href="http://www.neoaxis.com/ru" rel="nofollow">сайте</a><!--/noindex--> полно всяких <!--noindex--><a href="http://www.neoaxis.com/wiki/Документация/Статьи" rel="nofollow">руководств, документаций, туториалов, статей,</a><!--/noindex--> как на английском, так и на русском языках. Скачать можно и хелпник, и SDK, и демки и даже их исходный код (сам я пробую некоммерческую лицензию). Вот я и начну с исходного кода демо проекта (где уже включена RTS), который буду чуть чуть модифицировать, затачивая под свои нужды. Оговорюсь сразу - я не делаю полноценную стратегию, я просто хочу оценить насколько это затратно и реально ли вообще.<br/>
<br/>
Как известно, RTS состоит из нескольких компонентов:<br/>
1. Карта. Для этого разработчики движка заботливо приложили к SDK специальное приложение - редактор карт. Он позволяет работать с объектами карты, с персонажами и даже запускать симуляцию карты (то есть как она будет работать в игре). Также в редактор карт встроен редактор логики - то есть можно скриптовать различные сценарии не отходя от станка, так сказать. <br/>
<div style="text-align: center"><!--noindex--><a href="http://2.bp.blogspot.com/-WHAPt9kvCn4/TwXy7mOkv_I/AAAAAAAAC6Q/Obx7JH12FD8/s1600/1.PNG" rel="nofollow" style="margin-left: 1em; margin-right: 1em"><img src="http://2.bp.blogspot.com/-WHAPt9kvCn4/TwXy7mOkv_I/AAAAAAAAC6Q/Obx7JH12FD8/s640/1.PNG" width="640px" height="472px" border="0"/></a><!--/noindex--></div>2. Ресурсы. <br/>
К ресурсам относятся следующие типы игровых объектов:<br/>
<ul style="text-align: left"><li>трехмерные модели,</li>
 <li>физические модели,</li>
 <li>материалы,</li>
 <li>текстуры,</li>
 <li>интерфейсы,</li>
 <li>системы частиц,</li>
 <li>описания шрифтов,</li>
 <li>звуки,</li>
 <li>видео</li>
 </ul>Чтобы там не потеряться, в комплекте идет редактор ресурсов. В общем, я поработал над дизайном главного окна...<br/>
<div style="text-align: center"><!--noindex--><a href="http://1.bp.blogspot.com/-XzVVsrve8p0/TwX1ZmyzLjI/AAAAAAAAC6c/mhjpRaFUeF8/s1600/2.PNG" rel="nofollow" style="margin-left: 1em; margin-right: 1em"><img src="http://1.bp.blogspot.com/-XzVVsrve8p0/TwX1ZmyzLjI/AAAAAAAAC6c/mhjpRaFUeF8/s400/2.PNG" width="640px" border="0"/></a><!--/noindex--></div>3. Конфиг. Тут можно указывать настройки движка - рендера, звука и тд. Я вынес это как отдельный пункт, так как в поставке есть программа-конфигуратор.<br/>
<div style="text-align: center"><!--noindex--><a href="http://4.bp.blogspot.com/-EWoVLfoLgiY/TwX5D6HFUlI/AAAAAAAAC6o/784cyOlFowc/s1600/3.PNG" rel="nofollow" style="margin-left: 1em; margin-right: 1em"><img src="http://4.bp.blogspot.com/-EWoVLfoLgiY/TwX5D6HFUlI/AAAAAAAAC6o/784cyOlFowc/s400/3.PNG" border="0"/></a><!--/noindex--></div>4. Дополнительные инструменты<br/>
5. Ну, и, собственно, код<br/>
<br/>
Для ясности, приведу весь список инструментов, что идут с SDK<br/>
<ul><li> <!--noindex--><a href="http://www.neoaxis.com/wiki/File:ResourceEditorIcon.jpg" rel="nofollow"><img src="http://www.neoaxis.com/w/images/e/e8/ResourceEditorIcon.jpg" alt="ResourceEditorIcon.jpg" width="16px" height="16px" border="0"/></a><!--/noindex--> <!--noindex--><a title="Документация/Статьи/Обзор редактора ресурсов" href="http://www.neoaxis.com/wiki/Документация/Статьи/Обзор_редактора_ресурсов" rel="nofollow">Редактор ресурсов</a><!--/noindex--> - Редактор ресурсов предназначен для редактирования ресурсов проекта. Сюда входят, главным образом, трехмерные модели, карты, материалы, текстуры, звуки и прочее.<br/>
</li>
 <li> <!--noindex--><a href="http://www.neoaxis.com/wiki/File:MapEditorIcon.jpg" rel="nofollow"><img src="http://www.neoaxis.com/w/images/6/69/MapEditorIcon.jpg" alt="MapEditorIcon.jpg" width="16px" height="16px" border="0"/></a><!--/noindex--> <!--noindex--><a title="Документация/Статьи/Обзор редактора карт" href="http://www.neoaxis.com/wiki/Документация/Статьи/Обзор_редактора_карт" rel="nofollow">Редактор карт</a><!--/noindex--> - Редактор карт предназначен для создания и редактирования игровых карт.<br/>
</li>
 <li> <!--noindex--><a href="http://www.neoaxis.com/wiki/File:ConfiguratorIcon.jpg" rel="nofollow"><img src="http://www.neoaxis.com/w/images/a/a6/ConfiguratorIcon.jpg" alt="ConfiguratorIcon.jpg" width="16px" height="16px" border="0"/></a><!--/noindex--> <!--noindex--><a title="Документация/Статьи/Обзор конфигуратора" href="http://www.neoaxis.com/wiki/Документация/Статьи/Обзор_конфигуратора" rel="nofollow">Конфигуратор</a><!--/noindex--> - Утилита для настройки параметров движка.<br/>
</li>
 <li> <!--noindex--><a href="http://www.neoaxis.com/wiki/File:DeploymentToolIcon.jpg" rel="nofollow"><img src="http://www.neoaxis.com/w/images/8/8b/DeploymentToolIcon.jpg" alt="DeploymentToolIcon.jpg" width="16px" height="16px" border="0"/></a><!--/noindex--> <!--noindex--><a title="Документация/Статьи/Обзор Deployment Tool" href="http://www.neoaxis.com/wiki/Документация/Статьи/Обзор_Deployment_Tool" rel="nofollow">Deployment Tool</a><!--/noindex--> - Инструмент для подготовки конечного продукта.<br/>
</li>
 <li> <!--noindex--><a href="http://www.neoaxis.comwiki/File:UtilitiesIcon.jpg" rel="nofollow"><img src="http://www.neoaxis.com/w/images/a/a9/UtilitiesIcon.jpg" alt="UtilitiesIcon.jpg" width="16px" height="16px" border="0"/></a><!--/noindex--> <!--noindex--><a title="Документация/Статьи/Обзор компилятора кеша шейдеров" href="http://www.neoaxis.com/wiki/Документация/Статьи/Обзор_компилятора_кеша_шейдеров" rel="nofollow">Компилятор шейдеров</a><!--/noindex--> - Компилятор кэша шейдеров.<br/>
</li>
 </ul><br/>
Теперь к коду. <br/>
Сразу в солюшен включены несколько проектов:<br/>
<ul><li> <b>GameCommon</b> - Различные классы проекта, такие как, описание типов материалов, сетевые сервисы проекта, класс консоли движка, пользовательские гуи классы. </li>
 <li> <b>GameEntities</b> - Описание игровых классов и всей логики игры. </li>
 <li> <b>Game</b> - Точка входа приложения. Инициализация движка, классы для реализации структуры проекта, навигации игровых экранов и взаимодействия с пользователем. </li>
 <li> <b>ChatExample</b> - Пример реализации сетевого чата на базе Windows Forms. </li>
 <li> <b>DedicatedServer</b> - Приложение для создания выделенного сервера. </li>
 <li> <b>WinFormsAppExample</b> - Пример интеграции движка в Windows Forms приложение. </li>
 <li> <b>WPFAppExample</b> - Пример интеграции движка в WPF приложение. </li>
 </ul>Я оставил только первые 3, остальные за ненадобностью удалил. Далее мне надо было найти меню игры (ведь я менял ресурсы менюшек, а значит при запуске приложения те элементы, что я изменил или удалил не найдутся и приложение просто может отвалиться). Сделать это было несложно, класс MainMenuWindow лежит прямо в корне проекта. Заглянув в него, я увидел, как находятся кнопки окон и как вешаются на них обработчики. Мне оставалось только убрать ненужное и добавить то, что меня интересовало. <br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>//button handlers - ненужное просто закаментил</span></li>
 <li><span>//( (Button)window.Controls[ &quot;Run&quot; ] ).Click += Run_Click;</span></li>
 <li><span>//( (Button)window.Controls[ &quot;RunVillageDemo&quot; ] ).Click += RunVillageDemo_Click;</span></li>
 <li><span>//( (Button)window.Controls[ &quot;Multiplayer&quot; ] ).Click += Multiplayer_Click;</span></li>
 <li><span>//( (Button)window.Controls[ &quot;Maps&quot; ] ).Click += Maps_Click;</span></li>
 <li><span>//( (Button)window.Controls[ &quot;LoadSave&quot; ] ).Click += LoadSave_Click;</span></li>
 <li>( (<span>Button</span>)window.Controls[ <span>&quot;Options&quot;</span> ] ).Click += Options_Click;</li>
 <li><span>//( (Button)window.Controls[ &quot;Profiler&quot; ] ).Click += Profiler_Click;</span></li>
 <li><span>//( (Button)window.Controls[ &quot;GuiTest&quot; ] ).Click += GuiTest_Click;</span></li>
 <li><span>//( (Button)window.Controls[ &quot;About&quot; ] ).Click += About_Click;</span></li>
 <li>( (<span>Button</span>)window.Controls[ <span>&quot;Exit&quot;</span> ] ).Click += Exit_Click;</li>
 <li>&#160;</li>
 <li><span>// Добавляю обработчик на свою кнопку, которая грузит нужную мне карту</span></li>
 <li>((<span>Button</span>) window.Controls[<span>&quot;Play&quot;</span>]).Click += <span>delegate</span>(<span>Button</span> sender)</li>
 <li> {</li>
 <li> <span>var</span> file = <span>VirtualDirectory</span>.GetFiles(<span>@&quot;Maps\RTSDemo\&quot;</span>, <span>&quot;Map.map&quot;</span>, <span>SearchOption</span>.AllDirectories)[0];</li>
 <li> <span>GameEngineApp</span>.Instance.SetNeedMapLoad(file);</li>
 <li> };</li>
 </ol></div></div>Отлично. Теперь при запуске игры, она покажет отредактированное окно и кнопка &quot;Играть&quot; запустит нужную мне карту.<br/>
<div style="text-align: center"><!--noindex--><a href="http://2.bp.blogspot.com/-aLRiy06Fs9A/TwaS-lD7F-I/AAAAAAAAC60/Y5WViLDfXJ0/s1600/4.PNG" rel="nofollow" style="margin-left: 1em; margin-right: 1em"><img src="http://2.bp.blogspot.com/-aLRiy06Fs9A/TwaS-lD7F-I/AAAAAAAAC60/Y5WViLDfXJ0/s400/4.PNG" width="640px" border="0"/></a><!--/noindex--></div><div style="text-align: center"><!--noindex--><a href="http://3.bp.blogspot.com/-e_U9UmEOQ0Q/TwaUhlVQpSI/AAAAAAAAC7A/9AloXHTzAgM/s1600/5.PNG" rel="nofollow" style="margin-left: 1em; margin-right: 1em"><img src="http://3.bp.blogspot.com/-e_U9UmEOQ0Q/TwaUhlVQpSI/AAAAAAAAC7A/9AloXHTzAgM/s400/5.PNG" width="640px" border="0"/></a><!--/noindex--></div>Итак, на данный момент у нас есть карта с юнитами, есть главное меню, не хватает только AI. Не, ну, конечно, сейчас враги будут в нас стрелять и наши войска будут стрелять в них и кто то, очевидно, погибнет, но хочется как то этим процессом управлять. Для этого заглянем в проект GameEntities, а именно в класс RTSUnitAI.<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li><span>///</span><span> Defines the </span><span>&lt;see cref=&quot;RTSUnitAI&quot;/&gt;</span><span> entity type.</span></li>
 <li><span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li><span>public</span> <span>class</span> <span>RTSUnitAIType</span> : <span>AIType</span></li>
 <li>{</li>
 <li>}</li>
 <li>&#160;</li>
 <li><span>public</span> <span>class</span> <span>RTSUnitAI</span> : <span>AI</span></li>
 <li>{</li>
 <li> ................</li>
 <li>}</li>
 </ol></div></div>Насколько я понял, первый класс используется в редакторе ресурсов. А вот во втором творится самое чудесное - логика AI. Там довольно много кода, потому я решил написать класс логики персонажей с нуля, конечно, подглядывая в этот класс. Итак, начнем!<br/>
Сперва сделаем пустое AI<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>namespace</span> GameEntities</li>
 <li>{</li>
 <li> <span>public</span> <span>class</span> <span>RTSUnitMegaAIType</span> : <span>AIType</span></li>
 <li> {</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>public</span> <span>class</span> <span>RTSUnitMegaAI</span>: <span>AI</span></li>
 <li> {</li>
 <li> <span>RTSUnitMegaAIType</span> _type = <span>null</span>; <span>public</span> <span>new</span> <span>RTSUnitMegaAIType</span> Type { <span>get</span> { <span>return</span> _type; } }</li>
 <li> }</li>
 <li>}</li>
 </ol></div></div><br/>
После этого, в папке \Data\Types\RTSSpecific\AIs найдем файл DefaultRTSUnitAI.type, вот его содержимое<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2em; padding: 0 0 0 5px"><li>type DefaultRTSUnitAI</li>
 <li>{</li>
 <li> <span>class</span> = <span>RTSUnitAI</span></li>
 <li>}</li>
 </ol></div></div>Заменим на <br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2em; padding: 0 0 0 5px"><li>type DefaultRTSUnitAI</li>
 <li>{</li>
 <li> <span>class</span> = <span>RTSUnitMegaAI</span></li>
 <li>}</li>
 </ol></div></div><br/>
Запустив игру, можно заметить, что юниты теперь вообще ни на что не реагируют. Это понятно, ведь AI у них сейчас пустой! А давайте мотивируем их на что нибудь! :)<br/>
Самое главное, это перегрузить метод <br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2em; padding: 0 0 0 5px"><li><span>protected</span> <span>override</span> <span>void</span> OnTick()</li>
 </ol></div></div>тут варится вся логика нашего персонажа. Но перед этим нужно провести подготовительные работы. Так как я впервые работаю с этим движком, я буду потихоньку копировать логику из AI по умолчанию и, где надо, её затачивать для себя. <br/>
Итак, самое первое - это инициализация вооружения персонажа. Оружие используется как минимум для того, чтобы определить, может ли персонаж стрелять, и если может, то из какой точки выпускать анимированную пулю. Далее. нужно определиться с задачей, которую он выполняет - если текущая задача есть, то пусть действует по ней. Если задачи закончились - пусть ищет себе занятие сам. <br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 3em; padding: 0 0 0 5px"><li><span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li><span>///</span><span> Самый мозг юнита</span></li>
 <li><span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li><span>protected</span> <span>override</span> <span>void</span> OnTick()</li>
 <li>{</li>
 <li> <span>base</span>.OnTick();</li>
 <li> <span>// обновляем вооружение</span></li>
 <li> <span>if</span> (_initialWeapons == <span>null</span>)</li>
 <li> UpdateInitialWeapons();</li>
 <li>&#160;</li>
 <li> <span>// Выполняем шаг для текущей заачи</span></li>
 <li> TickTasks();</li>
 <li>&#160;</li>
 <li> <span>// Если задачи заканчиваются, ищем новую задачу</span></li>
 <li> <span>if</span> ((_currentTask.Type == <span>Task</span>.<span>Types</span>.Stop ||</li>
 <li> _currentTask.Type == <span>Task</span>.<span>Types</span>.BreakableMove ||</li>
 <li> _currentTask.Type == <span>Task</span>.<span>Types</span>.BreakableAttack ||</li>
 <li> _currentTask.Type == <span>Task</span>.<span>Types</span>.BreakableRepair</li>
 <li> ) &amp;&amp; _tasks.Count == 0)</li>
 <li> {</li>
 <li> _inactiveFindTaskTimer -= TickDelta;</li>
 <li> <span>if</span> (_inactiveFindTaskTimer &lt;= 0)</li>
 <li> {</li>
 <li> _inactiveFindTaskTimer += 1.0f;</li>
 <li> <span>if</span> (!InactiveFindTask())</li>
 <li> _inactiveFindTaskTimer += .5f;</li>
 <li> }</li>
 <li> }</li>
 <li>}</li>
 </ol></div></div><br/>
Весь остальной код, в основном, обслуживает этот метод. Думаю, ещё стоит привести код метода, который выполняет текущую задачу<br/>
<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 3em; padding: 0 0 0 5px"><li><span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li><span>///</span><span> Выполнение задачи</span></li>
 <li><span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li><span>protected</span> <span>virtual</span> <span>void</span> TickTasks()</li>
 <li>{</li>
 <li> <span>// Наш юнит</span></li>
 <li> <span>var</span> controlledObj = ControlledObject;</li>
 <li> <span>if</span> (controlledObj == <span>null</span>)</li>
 <li> <span>return</span>;</li>
 <li>&#160;</li>
 <li> <span>switch</span> (_currentTask.Type)</li>
 <li> {</li>
 <li>&#160;</li>
 <li> <span>// остановить юнит</span></li>
 <li> <span>case</span> <span>Task</span>.<span>Types</span>.Stop:</li>
 <li> controlledObj.Stop();</li>
 <li> <span>break</span>;</li>
 <li>&#160;</li>
 <li> <span>// движение</span></li>
 <li> <span>case</span> <span>Task</span>.<span>Types</span>.Move:</li>
 <li> <span>case</span> <span>Task</span>.<span>Types</span>.BreakableMove:</li>
 <li> <span>if</span> (_currentTask.Entity != <span>null</span>)</li>
 <li> {</li>
 <li> controlledObj.Move(_currentTask.Entity.Position);</li>
 <li> }</li>
 <li> <span>else</span></li>
 <li> {</li>
 <li> <span>var</span> pos = _currentTask.Position;</li>
 <li>&#160;</li>
 <li> <span>if</span> ((controlledObj.Position.ToVec2() - pos.ToVec2()).LengthFast() &lt; 1.5f &amp;&amp;</li>
 <li> <span>Math</span>.Abs(controlledObj.Position.Z - pos.Z) &lt; 3.0f)</li>
 <li> {</li>
 <li> DoNextTask();</li>
 <li> }</li>
 <li> <span>else</span></li>
 <li> controlledObj.Move(pos);</li>
 <li> }</li>
 <li> <span>break</span>;</li>
 <li>&#160;</li>
 <li> <span>// Атакуем или чиним</span></li>
 <li> <span>case</span> <span>Task</span>.<span>Types</span>.Attack:</li>
 <li> <span>case</span> <span>Task</span>.<span>Types</span>.BreakableAttack:</li>
 <li> <span>case</span> <span>Task</span>.<span>Types</span>.Repair:</li>
 <li> <span>case</span> <span>Task</span>.<span>Types</span>.BreakableRepair:</li>
 <li> {</li>
 <li> <span>// ремонт</span></li>
 <li> <span>if</span> ((_currentTask.Type == <span>Task</span>.<span>Types</span>.Repair ||</li>
 <li> _currentTask.Type == <span>Task</span>.<span>Types</span>.BreakableRepair)</li>
 <li> &amp;&amp; _currentTask.Entity != <span>null</span>)</li>
 <li> {</li>
 <li> <span>// проверяем, если жизней у робота достаточно, то прекращаем его чинить</span></li>
 <li> <span>if</span> (<span>Math</span>.Abs(_currentTask.Entity.Life - _currentTask.Entity.Type.LifeMax) &lt; 0.000001)</li>
 <li> {</li>
 <li> DoNextTask();</li>
 <li> <span>break</span>;</li>
 <li> }</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>// Оптимальное расстояние для возможности ремонта</span></li>
 <li> <span>var</span> needDistance = controlledObj.Type.OptimalAttackDistanceRange.Maximum;</li>
 <li>&#160;</li>
 <li> <span>// позиция юнита, которого чиним</span></li>
 <li> <span>Vec3</span> targetPos;</li>
 <li> <span>if</span> (_currentTask.Entity != <span>null</span>)</li>
 <li> targetPos = _currentTask.Entity.Position;</li>
 <li> <span>else</span></li>
 <li> targetPos = _currentTask.Position;</li>
 <li>&#160;</li>
 <li> <span>// расстояние между нашим юнитом и целью</span></li>
 <li> <span>var</span> distance = (controlledObj.Position - targetPos).LengthFast();</li>
 <li>&#160;</li>
 <li> <span>// если это расстояние не равно 0</span></li>
 <li> <span>if</span> (<span>Math</span>.Abs(distance - 0) &gt; 0.000001)</li>
 <li> {</li>
 <li> <span>var</span> lineVisibility = <span>false</span>;</li>
 <li> </li>
 <li> <span>// если луч для лечения может достать до цели</span></li>
 <li> <span>if</span> (distance &lt; needDistance)</li>
 <li> {</li>
 <li> lineVisibility = <span>true</span>;</li>
 <li>&#160;</li>
 <li> </li>
 <li> <span>var</span> start = _initialWeapons[0].Position;</li>
 <li> <span>var</span> ray = <span>new</span> <span>Ray</span>(start, targetPos - start);</li>
 <li>&#160;</li>
 <li> <span>var</span> piercingResult = <span>PhysicsWorld</span>.Instance.RayCastPiercing(</li>
 <li> ray, (<span>int</span>)<span>ContactGroup</span>.CastOnlyContact);</li>
 <li>&#160;</li>
 <li> <span>foreach</span> (<span>var</span> result <span>in</span> piercingResult)</li>
 <li> {</li>
 <li> <span>var</span> obj = <span>MapSystemWorld</span>.GetMapObjectByBody(result.Shape.Body);</li>
 <li>&#160;</li>
 <li> <span>if</span> (obj != <span>null</span> &amp;&amp; obj == _currentTask.Entity)</li>
 <li> <span>break</span>;</li>
 <li>&#160;</li>
 <li> <span>if</span> (obj != controlledObj)</li>
 <li> {</li>
 <li> lineVisibility = <span>false</span>;</li>
 <li> <span>break</span>;</li>
 <li> }</li>
 <li> }</li>
 <li> }</li>
 <li>&#160;</li>
 <li>&#160;</li>
 <li> <span>// если цель не в прямой видимости, то нужно повернуться к ней, или двигаться в её сторону</span></li>
 <li> <span>if</span> (lineVisibility)</li>
 <li> {</li>
 <li> controlledObj.Stop();</li>
 <li>&#160;</li>
 <li> <span>var</span> character = controlledObj <span>as</span> <span>RTSCharacter</span>;</li>
 <li> <span>if</span> (character != <span>null</span>)</li>
 <li> character.SetLookDirection(targetPos);</li>
 <li> }</li>
 <li> <span>else</span></li>
 <li> {</li>
 <li> controlledObj.Move(targetPos);</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>// тут проверяем, можем ли задействовать оружие. Если можем - то стреляем</span></li>
 <li> <span>if</span> (lineVisibility)</li>
 <li> {</li>
 <li> <span>foreach</span> (<span>Weapon</span> weapon <span>in</span> _initialWeapons)</li>
 <li> {</li>
 <li> <span>var</span> pos = targetPos;</li>
 <li> <span>var</span> gun = weapon <span>as</span> <span>Gun</span>;</li>
 <li> <span>if</span> (gun != <span>null</span> &amp;&amp; _currentTask.Entity != <span>null</span>)</li>
 <li> gun.GetAdvanceAttackTargetPosition(<span>false</span>, _currentTask.Entity, <span>false</span>, <span>out</span> pos);</li>
 <li> weapon.SetForceFireRotationLookTo(pos);</li>
 <li>&#160;</li>
 <li> <span>if</span> (weapon.Ready)</li>
 <li> {</li>
 <li> <span>var</span> range = weapon.Type.WeaponNormalMode.UseDistanceRange;</li>
 <li> <span>if</span> (distance &gt;= range.Minimum &amp;&amp; distance &lt;= range.Maximum)</li>
 <li> weapon.TryFire(<span>false</span>);</li>
 <li>&#160;</li>
 <li> range = weapon.Type.WeaponAlternativeMode.UseDistanceRange;</li>
 <li> <span>if</span> (distance &gt;= range.Minimum &amp;&amp; distance &lt;= range.Maximum)</li>
 <li> weapon.TryFire(<span>true</span>);</li>
 <li> }</li>
 <li> }</li>
 <li> }</li>
 <li> }</li>
 <li>&#160;</li>
 <li> }</li>
 <li> <span>break</span>;</li>
 <li> }</li>
 <li>}</li>
 </ol></div></div>Что касается структуры Task - её мы тоже определили в коде<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 3em; padding: 0 0 0 5px"><li><span>public</span> <span>struct</span> <span>Task</span></li>
 <li>{</li>
 <li> [<span>Entity</span>.<span>FieldSerializeAttribute</span>]</li>
 <li> [<span>DefaultValue</span>(<span>RTSUnitAI</span>.<span>Task</span>.<span>Types</span>.None)]</li>
 <li> <span>Types</span> type;</li>
 <li>&#160;</li>
 <li> [<span>Entity</span>.<span>FieldSerializeAttribute</span>]</li>
 <li> [<span>DefaultValue</span>(<span>typeof</span>(<span>Vec3</span>), <span>&quot;0 0 0&quot;</span>)]</li>
 <li> <span>Vec3</span> position;</li>
 <li>&#160;</li>
 <li> [<span>Entity</span>.<span>FieldSerializeAttribute</span>]</li>
 <li> <span>DynamicType</span> entityType;</li>
 <li>&#160;</li>
 <li> [<span>Entity</span>.<span>FieldSerializeAttribute</span>]</li>
 <li> <span>Dynamic</span> entity;</li>
 <li>&#160;</li>
 <li> <span>public</span> <span>enum</span> <span>Types</span></li>
 <li> {</li>
 <li> None,</li>
 <li> Stop,</li>
 <li> BreakableAttack,<span>//for automatic attacks</span></li>
 <li> Hold,</li>
 <li> Move,</li>
 <li> BreakableMove,<span>//for automatic attacks</span></li>
 <li> Attack,</li>
 <li> Repair,</li>
 <li> BreakableRepair,<span>//for automatic repair</span></li>
 <li> BuildBuilding,</li>
 <li> ProductUnit,</li>
 <li> SelfDestroy,<span>//for cancel build building </span></li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>public</span> Task(<span>Types</span> type)</li>
 <li> {</li>
 <li> <span>this</span>.type = type;</li>
 <li> <span>this</span>.position = <span>new</span> <span>Vec3</span>(<span>float</span>.NaN, <span>float</span>.NaN, <span>float</span>.NaN);</li>
 <li> <span>this</span>.entityType = <span>null</span>;</li>
 <li> <span>this</span>.entity = <span>null</span>;</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>public</span> Task(<span>Types</span> type, <span>Vec3</span> position)</li>
 <li> {</li>
 <li> <span>this</span>.type = type;</li>
 <li> <span>this</span>.position = position;</li>
 <li> <span>this</span>.entityType = <span>null</span>;</li>
 <li> <span>this</span>.entity = <span>null</span>;</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>public</span> Task(<span>Types</span> type, <span>DynamicType</span> entityType)</li>
 <li> {</li>
 <li> <span>this</span>.type = type;</li>
 <li> <span>this</span>.position = <span>new</span> <span>Vec3</span>(<span>float</span>.NaN, <span>float</span>.NaN, <span>float</span>.NaN);</li>
 <li> <span>this</span>.entityType = entityType;</li>
 <li> <span>this</span>.entity = <span>null</span>;</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>public</span> Task(<span>Types</span> type, <span>Vec3</span> position, <span>DynamicType</span> entityType)</li>
 <li> {</li>
 <li> <span>this</span>.type = type;</li>
 <li> <span>this</span>.position = position;</li>
 <li> <span>this</span>.entityType = entityType;</li>
 <li> <span>this</span>.entity = <span>null</span>;</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>public</span> Task(<span>Types</span> type, <span>Dynamic</span> entity)</li>
 <li> {</li>
 <li> <span>this</span>.type = type;</li>
 <li> <span>this</span>.position = <span>new</span> <span>Vec3</span>(<span>float</span>.NaN, <span>float</span>.NaN, <span>float</span>.NaN);</li>
 <li> <span>this</span>.entityType = <span>null</span>;</li>
 <li> <span>this</span>.entity = entity;</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>public</span> <span>Types</span> Type</li>
 <li> {</li>
 <li> <span>get</span> { <span>return</span> type; }</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>public</span> <span>Vec3</span> Position</li>
 <li> {</li>
 <li> <span>get</span> { <span>return</span> position; }</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>public</span> <span>DynamicType</span> EntityType</li>
 <li> {</li>
 <li> <span>get</span> { <span>return</span> entityType; }</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>public</span> <span>Dynamic</span> Entity</li>
 <li> {</li>
 <li> <span>get</span> { <span>return</span> entity; }</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>public</span> <span>override</span> <span>string</span> ToString()</li>
 <li> {</li>
 <li> <span>string</span> s = type.ToString();</li>
 <li> <span>if</span> (!<span>float</span>.IsNaN(position.X))</li>
 <li> s += <span>&quot;, Position: &quot;</span> + position.ToString();</li>
 <li> <span>if</span> (entityType != <span>null</span>)</li>
 <li> s += <span>&quot;, EntityType: &quot;</span> + entityType.Name;</li>
 <li> <span>if</span> (entity != <span>null</span>)</li>
 <li> s += <span>&quot;, Entity: &quot;</span> + entity.ToString();</li>
 <li> <span>return</span> s;</li>
 <li> }</li>
 <li>}</li>
 </ol></div></div><br/>
Теперь можно поработать и с AI. Например, у нас есть функция, которая определяет приоритет для атаки. Немного её модифицировав, можно повысить приоритет атаки робота-медика. То есть юниты будут атаковать сначала его, а потом военного робота. <br/>
<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 3em; padding: 0 0 0 5px"><li><span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li><span>///</span><span> Устанавливает приоритет для атаки</span></li>
 <li><span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li><span>///</span><span> </span><span>&lt;param name=&quot;obj&quot;&gt;&lt;/param&gt;</span></li>
 <li><span>///</span><span> </span><span>&lt;returns&gt;&lt;/returns&gt;</span></li>
 <li><span>protected</span> <span>float</span> GetAttackObjectPriority(<span>Unit</span> obj)</li>
 <li>{</li>
 <li> <span>if</span> (ControlledObject == obj)</li>
 <li> <span>return</span> 0;</li>
 <li>&#160;</li>
 <li> <span>if</span> (obj.Intellect == <span>null</span>)</li>
 <li> <span>return</span> 0;</li>
 <li>&#160;</li>
 <li> <span>//RTSConstructor specific</span></li>
 <li> <span>if</span> (ControlledObject.Type.Name == <span>&quot;RTSConstructor&quot;</span>)</li>
 <li> {</li>
 <li> <span>if</span> (Faction == obj.Intellect.Faction)</li>
 <li> {</li>
 <li> <span>if</span> (obj.Life &lt; obj.Type.LifeMax)</li>
 <li> {</li>
 <li> <span>Vec3</span> distance = obj.Position - ControlledObject.Position;</li>
 <li> <span>float</span> len = distance.LengthFast();</li>
 <li> <span>return</span> 1.0f / len + 1.0f;</li>
 <li> }</li>
 <li> }</li>
 <li> }</li>
 <li> <span>else</span></li>
 <li> {</li>
 <li> <span>if</span> (Faction != <span>null</span> &amp;&amp; obj.Intellect.Faction != <span>null</span> &amp;&amp; Faction != obj.Intellect.Faction)</li>
 <li> {</li>
 <li> <span>var</span> distance = obj.Position - ControlledObject.Position;</li>
 <li> <span>var</span> len = distance.LengthFast();</li>
 <li> <span>var</span> result = 1.0f / len + 1.0f;</li>
 <li> <span>// повышаем приоритет атаки на робота-медика</span></li>
 <li> <span>if</span> (obj.Type.Name == <span>&quot;RTSConstructor&quot;</span>) result = 1.1f/ len + 1.0f;</li>
 <li> <span>return</span> result;</li>
 <li> }</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>return</span> 0;</li>
 <li>}</li>
 </ol></div></div><br/>
Помимо всего этого, в игру можно добавить другие юниты и прописать им интеллект, изменить баланс игры, да вообще много чего можно сделать. Вот что у меня получилось в результате.<br/>
<br/>
<br/>
<br/>
Итак, имея готовый движок и демки, можно легко дорабатывать игру под себя. Ценители графики могут добавлять различные эффекты, реалистичные модели, анимации и много всего; искусственный интеллект тоже поддаётся изменению, так и вообще полной замене, а использование технологии .NET сильно упрощает работу. В заключение также хочется отметить, что трудозатраты на создание игры в данном случае были практически нулевые - 2 часа на изучение и кодинг и час на написание статьи. Это говорит о низком пороге вхождения в технологию. На этом всё. Всем спасибо.<br/>
</div><div><img src="https://blogger.googleusercontent.com/tracker/8897990838383834685-2631278028414084410?l=tym32167.blogspot.com" width="1px" height="1px" border="0"/></div>]]></description>
      <category><![CDATA[Neo Axis]]></category>
      <category><![CDATA[Game Engine]]></category>
      <category><![CDATA[Games]]></category>
      <category><![CDATA[.NET]]></category>
      <category><![CDATA[C#]]></category>
      <guid>http://tym32167.blogspot.com/2012/01/rts.html</guid>
      <pubDate>Fri, 06 Jan 2012 09:28:00 UT</pubDate>
      <dc:creator><![CDATA[tym32167]]></dc:creator>
    </item>
    <item>
      <title><![CDATA[Готовим стратегию в реальном времени (RTS) в домашних условиях]]></title>
      <link>http://microgeek.ru/blogs/tym32167/1722/</link>
      <description><![CDATA[<div style="text-align: left">Эх, давно хотел попробовать написать какую-нибудь игру. К тому же уже был опыт работы с 3D графикой, как с DirectX, так и с OpenGL, но всё некогда, некогда. Тогда я решил воспользоваться одним из готовых 3D движков, и поковырять его. Что из этого вышло...<br/>
<a name="more" rel="nofollow"></a><br/>
В общем, на хабре как то проскочила <!--noindex--><a href="http://habrahabr.ru/blogs/gdev/134937/" rel="nofollow">статья</a><!--/noindex--> о отечественном движке <!--noindex--><a href="http://www.neoaxis.com/ru" rel="nofollow">NeoAxis</a><!--/noindex-->. Давно его скачал, но вот только руки дошли поглядеть, что внутри. <br/>
Итак, движок, насколько я помню, основан на <!--noindex--><a href="http://www.ogre3d.org/" rel="nofollow">Ogre 3D</a><!--/noindex-->, работа с графикой написана на неуправляемом C++, вокруг которого наворотили обёрток и дали нам. простым смертным, писать под него логику на любом .NET языке. Имеет несколько вариантов <!--noindex--><a href="http://www.neoaxis.com/ru/neoaxis/licensing" rel="nofollow">лицензий</a><!--/noindex-->, в том числе и некоммерческую, которые отличаются ценой и возможностями. Также на <!--noindex--><a href="http://www.neoaxis.com/ru" rel="nofollow">сайте</a><!--/noindex--> полно всяких <!--noindex--><a href="http://www.neoaxis.com/wiki/Документация/Статьи" rel="nofollow">руководств, документаций, туториалов, статей,</a><!--/noindex--> как на английском, так и на русском языках. Скачать можно и хелпник, и SDK, и демки и даже их исходный код (сам я пробую некоммерческую лицензию). Вот я и начну с исходного кода демо проекта (где уже включена RTS), который буду чуть чуть модифицировать, затачивая под свои нужды. Оговорюсь сразу - я не делаю полноценную стратегию, я просто хочу оценить насколько это затратно и реально ли вообще.<br/>
<br/>
Как известно, RTS состоит из нескольких компонентов:<br/>
1. Карта. Для этого разработчики движка заботливо приложили к SDK специальное приложение - редактор карт. Он позволяет работать с объектами карты, с персонажами и даже запускать симуляцию карты (то есть как она будет работать в игре). Также в редактор карт встроен редактор логики - то есть можно скриптовать различные сценарии не отходя от станка, так сказать. <br/>
<div style="text-align: center"><!--noindex--><a href="http://2.bp.blogspot.com/-WHAPt9kvCn4/TwXy7mOkv_I/AAAAAAAAC6Q/Obx7JH12FD8/s1600/1.PNG" rel="nofollow" style="margin-left: 1em; margin-right: 1em"><img src="http://2.bp.blogspot.com/-WHAPt9kvCn4/TwXy7mOkv_I/AAAAAAAAC6Q/Obx7JH12FD8/s640/1.PNG" width="640px" height="472px" border="0"/></a><!--/noindex--></div>2. Ресурсы. <br/>
К ресурсам относятся следующие типы игровых объектов:<br/>
<ul style="text-align: left"><li>трехмерные модели,</li>
 <li>физические модели,</li>
 <li>материалы,</li>
 <li>текстуры,</li>
 <li>интерфейсы,</li>
 <li>системы частиц,</li>
 <li>описания шрифтов,</li>
 <li>звуки,</li>
 <li>видео</li>
 </ul>Чтобы там не потеряться, в комплекте идет редактор ресурсов. В общем, я поработал над дизайном главного окна...<br/>
<div style="text-align: center"><!--noindex--><a href="http://1.bp.blogspot.com/-XzVVsrve8p0/TwX1ZmyzLjI/AAAAAAAAC6c/mhjpRaFUeF8/s1600/2.PNG" rel="nofollow" style="margin-left: 1em; margin-right: 1em"><img src="http://1.bp.blogspot.com/-XzVVsrve8p0/TwX1ZmyzLjI/AAAAAAAAC6c/mhjpRaFUeF8/s400/2.PNG" width="640px" border="0"/></a><!--/noindex--></div>3. Конфиг. Тут можно указывать настройки движка - рендера, звука и тд. Я вынес это как отдельный пункт, так как в поставке есть программа-конфигуратор.<br/>
<div style="text-align: center"><!--noindex--><a href="http://4.bp.blogspot.com/-EWoVLfoLgiY/TwX5D6HFUlI/AAAAAAAAC6o/784cyOlFowc/s1600/3.PNG" rel="nofollow" style="margin-left: 1em; margin-right: 1em"><img src="http://4.bp.blogspot.com/-EWoVLfoLgiY/TwX5D6HFUlI/AAAAAAAAC6o/784cyOlFowc/s400/3.PNG" border="0"/></a><!--/noindex--></div>4. Дополнительные инструменты<br/>
5. Ну, и, собственно, код<br/>
<br/>
Для ясности, приведу весь список инструментов, что идут с SDK<br/>
<ul><li> <!--noindex--><a href="http://www.neoaxis.com/wiki/File:ResourceEditorIcon.jpg" rel="nofollow"><img src="http://www.neoaxis.com/w/images/e/e8/ResourceEditorIcon.jpg" alt="ResourceEditorIcon.jpg" width="16px" height="16px" border="0"/></a><!--/noindex--> <!--noindex--><a title="Документация/Статьи/Обзор редактора ресурсов" href="http://www.neoaxis.com/wiki/Документация/Статьи/Обзор_редактора_ресурсов" rel="nofollow">Редактор ресурсов</a><!--/noindex--> - Редактор ресурсов предназначен для редактирования ресурсов проекта. Сюда входят, главным образом, трехмерные модели, карты, материалы, текстуры, звуки и прочее.<br/>
</li>
 <li> <!--noindex--><a href="http://www.neoaxis.com/wiki/File:MapEditorIcon.jpg" rel="nofollow"><img src="http://www.neoaxis.com/w/images/6/69/MapEditorIcon.jpg" alt="MapEditorIcon.jpg" width="16px" height="16px" border="0"/></a><!--/noindex--> <!--noindex--><a title="Документация/Статьи/Обзор редактора карт" href="http://www.neoaxis.com/wiki/Документация/Статьи/Обзор_редактора_карт" rel="nofollow">Редактор карт</a><!--/noindex--> - Редактор карт предназначен для создания и редактирования игровых карт.<br/>
</li>
 <li> <!--noindex--><a href="http://www.neoaxis.com/wiki/File:ConfiguratorIcon.jpg" rel="nofollow"><img src="http://www.neoaxis.com/w/images/a/a6/ConfiguratorIcon.jpg" alt="ConfiguratorIcon.jpg" width="16px" height="16px" border="0"/></a><!--/noindex--> <!--noindex--><a title="Документация/Статьи/Обзор конфигуратора" href="http://www.neoaxis.com/wiki/Документация/Статьи/Обзор_конфигуратора" rel="nofollow">Конфигуратор</a><!--/noindex--> - Утилита для настройки параметров движка.<br/>
</li>
 <li> <!--noindex--><a href="http://www.neoaxis.com/wiki/File:DeploymentToolIcon.jpg" rel="nofollow"><img src="http://www.neoaxis.com/w/images/8/8b/DeploymentToolIcon.jpg" alt="DeploymentToolIcon.jpg" width="16px" height="16px" border="0"/></a><!--/noindex--> <!--noindex--><a title="Документация/Статьи/Обзор Deployment Tool" href="http://www.neoaxis.com/wiki/Документация/Статьи/Обзор_Deployment_Tool" rel="nofollow">Deployment Tool</a><!--/noindex--> - Инструмент для подготовки конечного продукта.<br/>
</li>
 <li> <!--noindex--><a href="http://www.neoaxis.comwiki/File:UtilitiesIcon.jpg" rel="nofollow"><img src="http://www.neoaxis.com/w/images/a/a9/UtilitiesIcon.jpg" alt="UtilitiesIcon.jpg" width="16px" height="16px" border="0"/></a><!--/noindex--> <!--noindex--><a title="Документация/Статьи/Обзор компилятора кеша шейдеров" href="http://www.neoaxis.com/wiki/Документация/Статьи/Обзор_компилятора_кеша_шейдеров" rel="nofollow">Компилятор шейдеров</a><!--/noindex--> - Компилятор кэша шейдеров.<br/>
</li>
 </ul><br/>
Теперь к коду. <br/>
Сразу в солюшен включены несколько проектов:<br/>
<ul><li> <b>GameCommon</b> - Различные классы проекта, такие как, описание типов материалов, сетевые сервисы проекта, класс консоли движка, пользовательские гуи классы. </li>
 <li> <b>GameEntities</b> - Описание игровых классов и всей логики игры. </li>
 <li> <b>Game</b> - Точка входа приложения. Инициализация движка, классы для реализации структуры проекта, навигации игровых экранов и взаимодействия с пользователем. </li>
 <li> <b>ChatExample</b> - Пример реализации сетевого чата на базе Windows Forms. </li>
 <li> <b>DedicatedServer</b> - Приложение для создания выделенного сервера. </li>
 <li> <b>WinFormsAppExample</b> - Пример интеграции движка в Windows Forms приложение. </li>
 <li> <b>WPFAppExample</b> - Пример интеграции движка в WPF приложение. </li>
 </ul>Я оставил только первые 3, остальные за ненадобностью удалил. Далее мне надо было найти меню игры (ведь я менял ресурсы менюшек, а значит при запуске приложения те элементы, что я изменил или удалил не найдутся и приложение просто может отвалиться). Сделать это было несложно, класс MainMenuWindow лежит прямо в корне проекта. Заглянув в него, я увидел, как находятся кнопки окон и как вешаются на них обработчики. Мне оставалось только убрать ненужное и добавить то, что меня интересовало. <br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>//button handlers - ненужное просто закаментил</span></li>
 <li><span>//( (Button)window.Controls[ &quot;Run&quot; ] ).Click += Run_Click;</span></li>
 <li><span>//( (Button)window.Controls[ &quot;RunVillageDemo&quot; ] ).Click += RunVillageDemo_Click;</span></li>
 <li><span>//( (Button)window.Controls[ &quot;Multiplayer&quot; ] ).Click += Multiplayer_Click;</span></li>
 <li><span>//( (Button)window.Controls[ &quot;Maps&quot; ] ).Click += Maps_Click;</span></li>
 <li><span>//( (Button)window.Controls[ &quot;LoadSave&quot; ] ).Click += LoadSave_Click;</span></li>
 <li>( (<span>Button</span>)window.Controls[ <span>&quot;Options&quot;</span> ] ).Click += Options_Click;</li>
 <li><span>//( (Button)window.Controls[ &quot;Profiler&quot; ] ).Click += Profiler_Click;</span></li>
 <li><span>//( (Button)window.Controls[ &quot;GuiTest&quot; ] ).Click += GuiTest_Click;</span></li>
 <li><span>//( (Button)window.Controls[ &quot;About&quot; ] ).Click += About_Click;</span></li>
 <li>( (<span>Button</span>)window.Controls[ <span>&quot;Exit&quot;</span> ] ).Click += Exit_Click;</li>
 <li>&#160;</li>
 <li><span>// Добавляю обработчик на свою кнопку, которая грузит нужную мне карту</span></li>
 <li>((<span>Button</span>) window.Controls[<span>&quot;Play&quot;</span>]).Click += <span>delegate</span>(<span>Button</span> sender)</li>
 <li> {</li>
 <li> <span>var</span> file = <span>VirtualDirectory</span>.GetFiles(<span>@&quot;Maps\RTSDemo\&quot;</span>, <span>&quot;Map.map&quot;</span>, <span>SearchOption</span>.AllDirectories)[0];</li>
 <li> <span>GameEngineApp</span>.Instance.SetNeedMapLoad(file);</li>
 <li> };</li>
 </ol></div></div>Отлично. Теперь при запуске игры, она покажет отредактированное окно и кнопка &quot;Играть&quot; запустит нужную мне карту.<br/>
<div style="text-align: center"><!--noindex--><a href="http://2.bp.blogspot.com/-aLRiy06Fs9A/TwaS-lD7F-I/AAAAAAAAC60/Y5WViLDfXJ0/s1600/4.PNG" rel="nofollow" style="margin-left: 1em; margin-right: 1em"><img src="http://2.bp.blogspot.com/-aLRiy06Fs9A/TwaS-lD7F-I/AAAAAAAAC60/Y5WViLDfXJ0/s400/4.PNG" width="640px" border="0"/></a><!--/noindex--></div><div style="text-align: center"><!--noindex--><a href="http://3.bp.blogspot.com/-e_U9UmEOQ0Q/TwaUhlVQpSI/AAAAAAAAC7A/9AloXHTzAgM/s1600/5.PNG" rel="nofollow" style="margin-left: 1em; margin-right: 1em"><img src="http://3.bp.blogspot.com/-e_U9UmEOQ0Q/TwaUhlVQpSI/AAAAAAAAC7A/9AloXHTzAgM/s400/5.PNG" width="640px" border="0"/></a><!--/noindex--></div>Итак, на данный момент у нас есть карта с юнитами, есть главное меню, не хватает только AI. Не, ну, конечно, сейчас враги будут в нас стрелять и наши войска будут стрелять в них и кто то, очевидно, погибнет, но хочется как то этим процессом управлять. Для этого заглянем в проект GameEntities, а именно в класс RTSUnitAI.<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li><span>///</span><span> Defines the </span><span>&lt;see cref=&quot;RTSUnitAI&quot;/&gt;</span><span> entity type.</span></li>
 <li><span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li><span>public</span> <span>class</span> <span>RTSUnitAIType</span> : <span>AIType</span></li>
 <li>{</li>
 <li>}</li>
 <li>&#160;</li>
 <li><span>public</span> <span>class</span> <span>RTSUnitAI</span> : <span>AI</span></li>
 <li>{</li>
 <li> ................</li>
 <li>}</li>
 </ol></div></div>Насколько я понял, первый класс используется в редакторе ресурсов. А вот во втором творится самое чудесное - логика AI. Там довольно много кода, потому я решил написать класс логики персонажей с нуля, конечно, подглядывая в этот класс. Итак, начнем!<br/>
Сперва сделаем пустое AI<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>namespace</span> GameEntities</li>
 <li>{</li>
 <li> <span>public</span> <span>class</span> <span>RTSUnitMegaAIType</span> : <span>AIType</span></li>
 <li> {</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>public</span> <span>class</span> <span>RTSUnitMegaAI</span>: <span>AI</span></li>
 <li> {</li>
 <li> <span>RTSUnitMegaAIType</span> _type = <span>null</span>; <span>public</span> <span>new</span> <span>RTSUnitMegaAIType</span> Type { <span>get</span> { <span>return</span> _type; } }</li>
 <li> }</li>
 <li>}</li>
 </ol></div></div><br/>
После этого, в папке \Data\Types\RTSSpecific\AIs найдем файл DefaultRTSUnitAI.type, вот его содержимое<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2em; padding: 0 0 0 5px"><li>type DefaultRTSUnitAI</li>
 <li>{</li>
 <li> <span>class</span> = <span>RTSUnitAI</span></li>
 <li>}</li>
 </ol></div></div>Заменим на <br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2em; padding: 0 0 0 5px"><li>type DefaultRTSUnitAI</li>
 <li>{</li>
 <li> <span>class</span> = <span>RTSUnitMegaAI</span></li>
 <li>}</li>
 </ol></div></div><br/>
Запустив игру, можно заметить, что юниты теперь вообще ни на что не реагируют. Это понятно, ведь AI у них сейчас пустой! А давайте мотивируем их на что нибудь! :)<br/>
Самое главное, это перегрузить метод <br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2em; padding: 0 0 0 5px"><li><span>protected</span> <span>override</span> <span>void</span> OnTick()</li>
 </ol></div></div>тут варится вся логика нашего персонажа. Но перед этим нужно провести подготовительные работы. Так как я впервые работаю с этим движком, я буду потихоньку копировать логику из AI по умолчанию и, где надо, её затачивать для себя. <br/>
Итак, самое первое - это инициализация вооружения персонажа. Оружие используется как минимум для того, чтобы определить, может ли персонаж стрелять, и если может, то из какой точки выпускать анимированную пулю. Далее. нужно определиться с задачей, которую он выполняет - если текущая задача есть, то пусть действует по ней. Если задачи закончились - пусть ищет себе занятие сам. <br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 3em; padding: 0 0 0 5px"><li><span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li><span>///</span><span> Самый мозг юнита</span></li>
 <li><span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li><span>protected</span> <span>override</span> <span>void</span> OnTick()</li>
 <li>{</li>
 <li> <span>base</span>.OnTick();</li>
 <li> <span>// обновляем вооружение</span></li>
 <li> <span>if</span> (_initialWeapons == <span>null</span>)</li>
 <li> UpdateInitialWeapons();</li>
 <li>&#160;</li>
 <li> <span>// Выполняем шаг для текущей заачи</span></li>
 <li> TickTasks();</li>
 <li>&#160;</li>
 <li> <span>// Если задачи заканчиваются, ищем новую задачу</span></li>
 <li> <span>if</span> ((_currentTask.Type == <span>Task</span>.<span>Types</span>.Stop ||</li>
 <li> _currentTask.Type == <span>Task</span>.<span>Types</span>.BreakableMove ||</li>
 <li> _currentTask.Type == <span>Task</span>.<span>Types</span>.BreakableAttack ||</li>
 <li> _currentTask.Type == <span>Task</span>.<span>Types</span>.BreakableRepair</li>
 <li> ) &amp;&amp; _tasks.Count == 0)</li>
 <li> {</li>
 <li> _inactiveFindTaskTimer -= TickDelta;</li>
 <li> <span>if</span> (_inactiveFindTaskTimer &lt;= 0)</li>
 <li> {</li>
 <li> _inactiveFindTaskTimer += 1.0f;</li>
 <li> <span>if</span> (!InactiveFindTask())</li>
 <li> _inactiveFindTaskTimer += .5f;</li>
 <li> }</li>
 <li> }</li>
 <li>}</li>
 </ol></div></div><br/>
Весь остальной код, в основном, обслуживает этот метод. Думаю, ещё стоит привести код метода, который выполняет текущую задачу<br/>
<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 3em; padding: 0 0 0 5px"><li><span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li><span>///</span><span> Выполнение задачи</span></li>
 <li><span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li><span>protected</span> <span>virtual</span> <span>void</span> TickTasks()</li>
 <li>{</li>
 <li> <span>// Наш юнит</span></li>
 <li> <span>var</span> controlledObj = ControlledObject;</li>
 <li> <span>if</span> (controlledObj == <span>null</span>)</li>
 <li> <span>return</span>;</li>
 <li>&#160;</li>
 <li> <span>switch</span> (_currentTask.Type)</li>
 <li> {</li>
 <li>&#160;</li>
 <li> <span>// остановить юнит</span></li>
 <li> <span>case</span> <span>Task</span>.<span>Types</span>.Stop:</li>
 <li> controlledObj.Stop();</li>
 <li> <span>break</span>;</li>
 <li>&#160;</li>
 <li> <span>// движение</span></li>
 <li> <span>case</span> <span>Task</span>.<span>Types</span>.Move:</li>
 <li> <span>case</span> <span>Task</span>.<span>Types</span>.BreakableMove:</li>
 <li> <span>if</span> (_currentTask.Entity != <span>null</span>)</li>
 <li> {</li>
 <li> controlledObj.Move(_currentTask.Entity.Position);</li>
 <li> }</li>
 <li> <span>else</span></li>
 <li> {</li>
 <li> <span>var</span> pos = _currentTask.Position;</li>
 <li>&#160;</li>
 <li> <span>if</span> ((controlledObj.Position.ToVec2() - pos.ToVec2()).LengthFast() &lt; 1.5f &amp;&amp;</li>
 <li> <span>Math</span>.Abs(controlledObj.Position.Z - pos.Z) &lt; 3.0f)</li>
 <li> {</li>
 <li> DoNextTask();</li>
 <li> }</li>
 <li> <span>else</span></li>
 <li> controlledObj.Move(pos);</li>
 <li> }</li>
 <li> <span>break</span>;</li>
 <li>&#160;</li>
 <li> <span>// Атакуем или чиним</span></li>
 <li> <span>case</span> <span>Task</span>.<span>Types</span>.Attack:</li>
 <li> <span>case</span> <span>Task</span>.<span>Types</span>.BreakableAttack:</li>
 <li> <span>case</span> <span>Task</span>.<span>Types</span>.Repair:</li>
 <li> <span>case</span> <span>Task</span>.<span>Types</span>.BreakableRepair:</li>
 <li> {</li>
 <li> <span>// ремонт</span></li>
 <li> <span>if</span> ((_currentTask.Type == <span>Task</span>.<span>Types</span>.Repair ||</li>
 <li> _currentTask.Type == <span>Task</span>.<span>Types</span>.BreakableRepair)</li>
 <li> &amp;&amp; _currentTask.Entity != <span>null</span>)</li>
 <li> {</li>
 <li> <span>// проверяем, если жизней у робота достаточно, то прекращаем его чинить</span></li>
 <li> <span>if</span> (<span>Math</span>.Abs(_currentTask.Entity.Life - _currentTask.Entity.Type.LifeMax) &lt; 0.000001)</li>
 <li> {</li>
 <li> DoNextTask();</li>
 <li> <span>break</span>;</li>
 <li> }</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>// Оптимальное расстояние для возможности ремонта</span></li>
 <li> <span>var</span> needDistance = controlledObj.Type.OptimalAttackDistanceRange.Maximum;</li>
 <li>&#160;</li>
 <li> <span>// позиция юнита, которого чиним</span></li>
 <li> <span>Vec3</span> targetPos;</li>
 <li> <span>if</span> (_currentTask.Entity != <span>null</span>)</li>
 <li> targetPos = _currentTask.Entity.Position;</li>
 <li> <span>else</span></li>
 <li> targetPos = _currentTask.Position;</li>
 <li>&#160;</li>
 <li> <span>// расстояние между нашим юнитом и целью</span></li>
 <li> <span>var</span> distance = (controlledObj.Position - targetPos).LengthFast();</li>
 <li>&#160;</li>
 <li> <span>// если это расстояние не равно 0</span></li>
 <li> <span>if</span> (<span>Math</span>.Abs(distance - 0) &gt; 0.000001)</li>
 <li> {</li>
 <li> <span>var</span> lineVisibility = <span>false</span>;</li>
 <li> </li>
 <li> <span>// если луч для лечения может достать до цели</span></li>
 <li> <span>if</span> (distance &lt; needDistance)</li>
 <li> {</li>
 <li> lineVisibility = <span>true</span>;</li>
 <li>&#160;</li>
 <li> </li>
 <li> <span>var</span> start = _initialWeapons[0].Position;</li>
 <li> <span>var</span> ray = <span>new</span> <span>Ray</span>(start, targetPos - start);</li>
 <li>&#160;</li>
 <li> <span>var</span> piercingResult = <span>PhysicsWorld</span>.Instance.RayCastPiercing(</li>
 <li> ray, (<span>int</span>)<span>ContactGroup</span>.CastOnlyContact);</li>
 <li>&#160;</li>
 <li> <span>foreach</span> (<span>var</span> result <span>in</span> piercingResult)</li>
 <li> {</li>
 <li> <span>var</span> obj = <span>MapSystemWorld</span>.GetMapObjectByBody(result.Shape.Body);</li>
 <li>&#160;</li>
 <li> <span>if</span> (obj != <span>null</span> &amp;&amp; obj == _currentTask.Entity)</li>
 <li> <span>break</span>;</li>
 <li>&#160;</li>
 <li> <span>if</span> (obj != controlledObj)</li>
 <li> {</li>
 <li> lineVisibility = <span>false</span>;</li>
 <li> <span>break</span>;</li>
 <li> }</li>
 <li> }</li>
 <li> }</li>
 <li>&#160;</li>
 <li>&#160;</li>
 <li> <span>// если цель не в прямой видимости, то нужно повернуться к ней, или двигаться в её сторону</span></li>
 <li> <span>if</span> (lineVisibility)</li>
 <li> {</li>
 <li> controlledObj.Stop();</li>
 <li>&#160;</li>
 <li> <span>var</span> character = controlledObj <span>as</span> <span>RTSCharacter</span>;</li>
 <li> <span>if</span> (character != <span>null</span>)</li>
 <li> character.SetLookDirection(targetPos);</li>
 <li> }</li>
 <li> <span>else</span></li>
 <li> {</li>
 <li> controlledObj.Move(targetPos);</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>// тут проверяем, можем ли задействовать оружие. Если можем - то стреляем</span></li>
 <li> <span>if</span> (lineVisibility)</li>
 <li> {</li>
 <li> <span>foreach</span> (<span>Weapon</span> weapon <span>in</span> _initialWeapons)</li>
 <li> {</li>
 <li> <span>var</span> pos = targetPos;</li>
 <li> <span>var</span> gun = weapon <span>as</span> <span>Gun</span>;</li>
 <li> <span>if</span> (gun != <span>null</span> &amp;&amp; _currentTask.Entity != <span>null</span>)</li>
 <li> gun.GetAdvanceAttackTargetPosition(<span>false</span>, _currentTask.Entity, <span>false</span>, <span>out</span> pos);</li>
 <li> weapon.SetForceFireRotationLookTo(pos);</li>
 <li>&#160;</li>
 <li> <span>if</span> (weapon.Ready)</li>
 <li> {</li>
 <li> <span>var</span> range = weapon.Type.WeaponNormalMode.UseDistanceRange;</li>
 <li> <span>if</span> (distance &gt;= range.Minimum &amp;&amp; distance &lt;= range.Maximum)</li>
 <li> weapon.TryFire(<span>false</span>);</li>
 <li>&#160;</li>
 <li> range = weapon.Type.WeaponAlternativeMode.UseDistanceRange;</li>
 <li> <span>if</span> (distance &gt;= range.Minimum &amp;&amp; distance &lt;= range.Maximum)</li>
 <li> weapon.TryFire(<span>true</span>);</li>
 <li> }</li>
 <li> }</li>
 <li> }</li>
 <li> }</li>
 <li>&#160;</li>
 <li> }</li>
 <li> <span>break</span>;</li>
 <li> }</li>
 <li>}</li>
 </ol></div></div>Что касается структуры Task - её мы тоже определили в коде<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 3em; padding: 0 0 0 5px"><li><span>public</span> <span>struct</span> <span>Task</span></li>
 <li>{</li>
 <li> [<span>Entity</span>.<span>FieldSerializeAttribute</span>]</li>
 <li> [<span>DefaultValue</span>(<span>RTSUnitAI</span>.<span>Task</span>.<span>Types</span>.None)]</li>
 <li> <span>Types</span> type;</li>
 <li>&#160;</li>
 <li> [<span>Entity</span>.<span>FieldSerializeAttribute</span>]</li>
 <li> [<span>DefaultValue</span>(<span>typeof</span>(<span>Vec3</span>), <span>&quot;0 0 0&quot;</span>)]</li>
 <li> <span>Vec3</span> position;</li>
 <li>&#160;</li>
 <li> [<span>Entity</span>.<span>FieldSerializeAttribute</span>]</li>
 <li> <span>DynamicType</span> entityType;</li>
 <li>&#160;</li>
 <li> [<span>Entity</span>.<span>FieldSerializeAttribute</span>]</li>
 <li> <span>Dynamic</span> entity;</li>
 <li>&#160;</li>
 <li> <span>public</span> <span>enum</span> <span>Types</span></li>
 <li> {</li>
 <li> None,</li>
 <li> Stop,</li>
 <li> BreakableAttack,<span>//for automatic attacks</span></li>
 <li> Hold,</li>
 <li> Move,</li>
 <li> BreakableMove,<span>//for automatic attacks</span></li>
 <li> Attack,</li>
 <li> Repair,</li>
 <li> BreakableRepair,<span>//for automatic repair</span></li>
 <li> BuildBuilding,</li>
 <li> ProductUnit,</li>
 <li> SelfDestroy,<span>//for cancel build building </span></li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>public</span> Task(<span>Types</span> type)</li>
 <li> {</li>
 <li> <span>this</span>.type = type;</li>
 <li> <span>this</span>.position = <span>new</span> <span>Vec3</span>(<span>float</span>.NaN, <span>float</span>.NaN, <span>float</span>.NaN);</li>
 <li> <span>this</span>.entityType = <span>null</span>;</li>
 <li> <span>this</span>.entity = <span>null</span>;</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>public</span> Task(<span>Types</span> type, <span>Vec3</span> position)</li>
 <li> {</li>
 <li> <span>this</span>.type = type;</li>
 <li> <span>this</span>.position = position;</li>
 <li> <span>this</span>.entityType = <span>null</span>;</li>
 <li> <span>this</span>.entity = <span>null</span>;</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>public</span> Task(<span>Types</span> type, <span>DynamicType</span> entityType)</li>
 <li> {</li>
 <li> <span>this</span>.type = type;</li>
 <li> <span>this</span>.position = <span>new</span> <span>Vec3</span>(<span>float</span>.NaN, <span>float</span>.NaN, <span>float</span>.NaN);</li>
 <li> <span>this</span>.entityType = entityType;</li>
 <li> <span>this</span>.entity = <span>null</span>;</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>public</span> Task(<span>Types</span> type, <span>Vec3</span> position, <span>DynamicType</span> entityType)</li>
 <li> {</li>
 <li> <span>this</span>.type = type;</li>
 <li> <span>this</span>.position = position;</li>
 <li> <span>this</span>.entityType = entityType;</li>
 <li> <span>this</span>.entity = <span>null</span>;</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>public</span> Task(<span>Types</span> type, <span>Dynamic</span> entity)</li>
 <li> {</li>
 <li> <span>this</span>.type = type;</li>
 <li> <span>this</span>.position = <span>new</span> <span>Vec3</span>(<span>float</span>.NaN, <span>float</span>.NaN, <span>float</span>.NaN);</li>
 <li> <span>this</span>.entityType = <span>null</span>;</li>
 <li> <span>this</span>.entity = entity;</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>public</span> <span>Types</span> Type</li>
 <li> {</li>
 <li> <span>get</span> { <span>return</span> type; }</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>public</span> <span>Vec3</span> Position</li>
 <li> {</li>
 <li> <span>get</span> { <span>return</span> position; }</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>public</span> <span>DynamicType</span> EntityType</li>
 <li> {</li>
 <li> <span>get</span> { <span>return</span> entityType; }</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>public</span> <span>Dynamic</span> Entity</li>
 <li> {</li>
 <li> <span>get</span> { <span>return</span> entity; }</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>public</span> <span>override</span> <span>string</span> ToString()</li>
 <li> {</li>
 <li> <span>string</span> s = type.ToString();</li>
 <li> <span>if</span> (!<span>float</span>.IsNaN(position.X))</li>
 <li> s += <span>&quot;, Position: &quot;</span> + position.ToString();</li>
 <li> <span>if</span> (entityType != <span>null</span>)</li>
 <li> s += <span>&quot;, EntityType: &quot;</span> + entityType.Name;</li>
 <li> <span>if</span> (entity != <span>null</span>)</li>
 <li> s += <span>&quot;, Entity: &quot;</span> + entity.ToString();</li>
 <li> <span>return</span> s;</li>
 <li> }</li>
 <li>}</li>
 </ol></div></div><br/>
Теперь можно поработать и с AI. Например, у нас есть функция, которая определяет приоритет для атаки. Немного её модифицировав, можно повысить приоритет атаки робота-медика. То есть юниты будут атаковать сначала его, а потом военного робота. <br/>
<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 3em; padding: 0 0 0 5px"><li><span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li><span>///</span><span> Устанавливает приоритет для атаки</span></li>
 <li><span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li><span>///</span><span> </span><span>&lt;param name=&quot;obj&quot;&gt;&lt;/param&gt;</span></li>
 <li><span>///</span><span> </span><span>&lt;returns&gt;&lt;/returns&gt;</span></li>
 <li><span>protected</span> <span>float</span> GetAttackObjectPriority(<span>Unit</span> obj)</li>
 <li>{</li>
 <li> <span>if</span> (ControlledObject == obj)</li>
 <li> <span>return</span> 0;</li>
 <li>&#160;</li>
 <li> <span>if</span> (obj.Intellect == <span>null</span>)</li>
 <li> <span>return</span> 0;</li>
 <li>&#160;</li>
 <li> <span>//RTSConstructor specific</span></li>
 <li> <span>if</span> (ControlledObject.Type.Name == <span>&quot;RTSConstructor&quot;</span>)</li>
 <li> {</li>
 <li> <span>if</span> (Faction == obj.Intellect.Faction)</li>
 <li> {</li>
 <li> <span>if</span> (obj.Life &lt; obj.Type.LifeMax)</li>
 <li> {</li>
 <li> <span>Vec3</span> distance = obj.Position - ControlledObject.Position;</li>
 <li> <span>float</span> len = distance.LengthFast();</li>
 <li> <span>return</span> 1.0f / len + 1.0f;</li>
 <li> }</li>
 <li> }</li>
 <li> }</li>
 <li> <span>else</span></li>
 <li> {</li>
 <li> <span>if</span> (Faction != <span>null</span> &amp;&amp; obj.Intellect.Faction != <span>null</span> &amp;&amp; Faction != obj.Intellect.Faction)</li>
 <li> {</li>
 <li> <span>var</span> distance = obj.Position - ControlledObject.Position;</li>
 <li> <span>var</span> len = distance.LengthFast();</li>
 <li> <span>var</span> result = 1.0f / len + 1.0f;</li>
 <li> <span>// повышаем приоритет атаки на робота-медика</span></li>
 <li> <span>if</span> (obj.Type.Name == <span>&quot;RTSConstructor&quot;</span>) result = 1.1f/ len + 1.0f;</li>
 <li> <span>return</span> result;</li>
 <li> }</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>return</span> 0;</li>
 <li>}</li>
 </ol></div></div><br/>
Помимо всего этого, в игру можно добавить другие юниты и прописать им интеллект, изменить баланс игры, да вообще много чего можно сделать. Вот что у меня получилось в результате.<br/>
<br/>
<br/>
<br/>
Итак, имея готовый движок и демки, можно легко дорабатывать игру под себя. Ценители графики могут добавлять различные эффекты, реалистичные модели, анимации и много всего; искусственный интеллект тоже поддаётся изменению, так и вообще полной замене, а использование технологии .NET сильно упрощает работу. В заключение также хочется отметить, что трудозатраты на создание игры в данном случае были практически нулевые - 2 часа на изучение и кодинг и час на написание статьи. Это говорит о низком пороге вхождения в технологию. На этом всё. Всем спасибо.<br/>
</div><div><img src="https://blogger.googleusercontent.com/tracker/8897990838383834685-2631278028414084410?l=tym32167.blogspot.com" width="1px" height="1px" border="0"/></div>]]></description>
      <category><![CDATA[Neo Axis]]></category>
      <category><![CDATA[Game Engine]]></category>
      <category><![CDATA[Games]]></category>
      <category><![CDATA[.NET]]></category>
      <category><![CDATA[C#]]></category>
      <guid>http://feedproxy.google.com/~r/tym32167/~3/keQ-oQugaes/rts.html</guid>
      <pubDate>Fri, 06 Jan 2012 09:28:00 UT</pubDate>
      <dc:creator><![CDATA[tym32167]]></dc:creator>
    </item>
    <item>
      <title><![CDATA[Разрабатываем простой калькулятор на Silverlight и Windows Phone 7]]></title>
      <link>http://microgeek.ru/blogs/tym32167/1715/</link>
      <description><![CDATA[<div style="text-align: left">На новый год сделал себе подарок - телефон <!--noindex--><a href="http://www.samsungomniaw.ru/" rel="nofollow">Samsung Omnia W</a><!--/noindex--> под управлением прекрасной Windows Phone 7. Естественно, попробовать что то написать для этого телефона было вопросом времени. Я выбрал калькулятор, так как это самый простой способ показать, насколько легко начать программировать под WP7, даже не используя никаких сенсоров/датчиков. В результате я получил работающее приложение с кучей функций, а также библиотеку расчёта математических выражений. Вот как это выглядит<br/>
<br/>
<div style="text-align: center"><!--noindex--><a href="http://2.bp.blogspot.com/-B2X9inyJomo/TwGhPl3I2cI/AAAAAAAAC5g/HedWuCojlTg/s1600/s1.png" rel="nofollow" style="margin-left: 1em; margin-right: 1em"><img src="http://2.bp.blogspot.com/-B2X9inyJomo/TwGhPl3I2cI/AAAAAAAAC5g/HedWuCojlTg/s400/s1.png" width="240px" height="400px" border="0"/></a><!--/noindex--></div><br/>
<div style="text-align: center"><!--noindex--><a href="http://3.bp.blogspot.com/-0UfNDeoD9c8/TwGhTalS7pI/AAAAAAAAC5s/46JmpW7WUGM/s1600/s2.png" rel="nofollow" style="margin-left: 1em; margin-right: 1em"><img src="http://3.bp.blogspot.com/-0UfNDeoD9c8/TwGhTalS7pI/AAAAAAAAC5s/46JmpW7WUGM/s400/s2.png" width="240px" height="400px" border="0"/></a><!--/noindex--></div><br/>
Под катом описание процесса разработки.<br/>
<a name="more" rel="nofollow"></a><br/>
Общее описание того, что я хочу получить:<br/>
1. Будет простой текстбокс, выражение в который можно будет записать как кнопками калькулятора, так и встроенной клавиатурой.<br/>
2. По нажатию кнопки &quot;=&quot; будет происходить разбор указанного выражения и результаты разбора появятся под текстбоксом<br/>
3. Поскольку кнопок будет немало, я использую панорамное представление. То есть наборы кнопок можно будет просто пролистывать.<br/>
<br/>
Теперь о разборе выражения. Пожалуй, это можно было бы вынести и в отдельный пост, но я опишу тут, так как это неотъемлемая часть разрабатываемого калькулятора. Итак, выражения:<br/>
1. Библиотека обработки должна быть легкой и гибкой в настройке. <br/>
2. Первоначально я планирую разбирать только унарные и бинарные операции, унарные функции. Бинарный функции я пока не буду рассматривать.<br/>
<br/>
<div style="text-align: center">&#160;<b><span style="font-size: large">Часть 1. Разработка библиотеки парсинга выражений</span></b></div><br/>
Рассмотрим выражение. Выражение содержит в себе строковое своё представление и может быть вычисляемым, или не вычисляемым, если разрешить строковое представление не удастся<br/>
<br/>
<div style="color: black; font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2em; padding: 0 0 0 5px"><li><span style="color: blue">public</span> <span style="color: blue">interface</span> <span>IExpression</span></li>
 <li>{</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">double</span> Value { <span style="color: blue">get</span>; }</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">bool</span> HasValue { <span style="color: blue">get</span>; }</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">string</span> StringExpression { <span style="color: blue">get</span>; }</li>
 <li>}</li>
 </ol></div></div><br/>
Далее. Выражение состоит из операндов и операций. Операция = это действие над операндами. А операнды - это те же выражения. То есть операция - это по сути действие над одним или более выражением, позволяющее получить результат. <br/>
<br/>
<div style="color: black; font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2em; padding: 0 0 0 5px"><li><span style="color: blue">public</span> <span style="color: blue">interface</span> <span>IOperation</span></li>
 <li>{</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">double</span> Value { <span style="color: blue">get</span>; }</li>
 <li>}</li>
 </ol></div></div><br/>
Я буду рассматривать 2 варианта операций: бинарные и унарные. То есть с двумя операндами (сложение, вычитание) и с одним операндом (синус, косинус).<br/>
<br/>
Унарная операция<br/>
<br/>
<div style="color: black; font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span style="color: blue">public</span> <span style="color: blue">abstract</span> <span style="color: blue">class</span> <span>UnaryOperation</span> : <span>IOperation</span></li>
 <li>{</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">protected</span> <span style="color: blue">readonly</span> <span>IExpression</span> Ex;</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">protected</span> UnaryOperation(<span>IExpression</span> ex)</li>
 <li>&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Ex = ex;</li>
 <li>&#160;&#160;&#160;&#160;}</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">#region</span> Implementation of IOperation</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">public</span> <span style="color: blue">abstract</span> <span style="color: blue">double</span> Value { <span style="color: blue">get</span>; }</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">#endregion</span></li>
 <li>}</li>
 </ol></div></div><br/>
Бинарная операция<br/>
<br/>
<div style="color: black; font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span style="color: blue">public</span> <span style="color: blue">abstract</span> <span style="color: blue">class</span> <span>BinaryOperation</span> : <span>IOperation</span></li>
 <li>{</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">protected</span> <span style="color: blue">readonly</span> <span>IExpression</span> Ex1;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">protected</span> <span style="color: blue">readonly</span> <span>IExpression</span> Ex2;</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">protected</span> BinaryOperation(<span>IExpression</span> exp1, <span>IExpression</span> exp2)</li>
 <li>&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Ex1 = exp1;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Ex2 = exp2;</li>
 <li>&#160;&#160;&#160;&#160;}</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">#region</span> Implementation of IOperation</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">public</span> <span style="color: blue">abstract</span> <span style="color: blue">double</span> Value { <span style="color: blue">get</span>; }</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">#endregion</span></li>
 <li>}</li>
 </ol></div></div><br/>
Как пример, покажу реализацию бинарной операции, основанной на лямбда выражении. <br/>
<br/>
<br/>
<div style="color: black; font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span style="color: blue">public</span> <span style="color: blue">class</span> <span>LabdaBinaryOperation</span> : <span>BinaryOperation</span></li>
 <li>{</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">private</span> <span style="color: blue">readonly</span> <span>Func</span>&lt;<span style="color: blue">double</span>, <span style="color: blue">double</span>, <span style="color: blue">double</span>&gt; _func;</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">public</span> LabdaBinaryOperation(<span>Func</span>&lt;<span style="color: blue">double</span>, <span style="color: blue">double</span>, <span style="color: blue">double</span>&gt; func, <span>IExpression</span> exp1, <span>IExpression</span> exp2) : <span style="color: blue">base</span>(exp1, exp2)</li>
 <li>&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;_func = func;</li>
 <li>&#160;&#160;&#160;&#160;}</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">public</span> <span style="color: blue">override</span> <span style="color: blue">double</span> Value</li>
 <li>&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">get</span> { <span style="color: blue">return</span> _func(Ex1.Value, Ex2.Value); }</li>
 <li>&#160;&#160;&#160;&#160;}</li>
 <li>}</li>
 </ol></div></div><br/>
Отлично. У нас есть выражение и операция. Но как можно определить, какое выражение сожержит какую операцию? Для того, чтобы определить операцию по строковому выражению, я определил интерфейс, который возвращает операцию по строковому выражению<br/>
<br/>
<div style="color: black; font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2em; padding: 0 0 0 5px"><li><span style="color: blue">public</span> <span style="color: blue">interface</span> <span>IOperationExecutor</span></li>
 <li>{</li>
 <li>&#160;&#160;&#160;&#160;<span>IOperation</span> GetOperation(<span style="color: blue">string</span> expression);</li>
 <li>}</li>
 </ol></div></div><br/>
Очевидно, логика класса OperationExecutor будет довольно сложная. Поэтому я ввёл 4 дополнительные абстракции IUnaryOperationProvider, IBinaryOperationProvider, IOperationRecognizer, IOperationRecognizerProvider. IOperationRecognizer - это объект, который содержит сигнатуру операции, и если он встречает совпадение сигнатуры и самой операции, то, используюя один из объектов IUnaryOperationProvider или IBinaryOperationProvider, создаёт операцию. <br/>
<br/>
<div style="color: black; font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2em; padding: 0 0 0 5px"><li><span style="color: blue">public</span> <span style="color: blue">interface</span> <span>IOperationRecognizer</span></li>
 <li>{</li>
 <li>&#160;&#160;&#160;&#160;<span>IOperation</span> Recognize(<span style="color: blue">string</span> expression, <span>IOperationExecutor</span> operationExecutor);</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">int</span> Index(<span style="color: blue">string</span> expression, <span>IOperationExecutor</span> operationExecutor);</li>
 <li>}</li>
 </ol></div></div><br/>
Объект IOperationRecognizerProvider определяет приоритет операций и, соответственно, порядок разбора выражения. <br/>
<br/>
<div style="color: black; font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2em; padding: 0 0 0 5px"><li><span style="color: blue">public</span> <span style="color: blue">interface</span> <span>IOperationRecognizerProvider</span></li>
 <li>{</li>
 <li>&#160;&#160;&#160;&#160;<span>IEnumerable</span>&lt;<span>IEnumerable</span>&lt;<span>IOperationRecognizer</span>&gt;&gt; GetRecognizers();</li>
 <li>}</li>
 </ol></div></div><br/>
В итоге, весь процесс разбора выражения выглядит следующим образом:<br/>
1. Выражение получает строку и объект IOperationExecutor, который даст доступ к операции.<br/>
<br/>
<div style="color: black; font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span style="color: blue">public</span> <span style="color: blue">sealed</span> <span style="color: blue">class</span> <span>Expression</span> : <span>IExpression</span></li>
 <li>{</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">private</span> <span style="color: blue">readonly</span> <span style="color: blue">string</span> _expression;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">private</span> <span style="color: blue">readonly</span> <span>IOperationExecutor</span> _operationExecutor;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">private</span> <span>IOperation</span> _operation;</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">public</span> <span style="color: blue">static</span> <span>Expression</span> Create(<span style="color: blue">string</span> expression, <span>IOperationExecutor</span> operationExecutor)</li>
 <li>&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">return</span> <span style="color: blue">new</span> <span>Expression</span>(expression, operationExecutor);</li>
 <li>&#160;&#160;&#160;&#160;}</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">private</span> Expression(<span style="color: blue">string</span> expression, <span>IOperationExecutor</span> operationExecutor)</li>
 <li>&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;_expression = expression;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;_operationExecutor = operationExecutor;</li>
 <li>&#160;&#160;&#160;&#160;}</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">#region</span> Implementation of IExpression</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">public</span> <span style="color: blue">string</span> StringExpression</li>
 <li>&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">get</span> { <span style="color: blue">return</span> _expression; }</li>
 <li>&#160;&#160;&#160;&#160;}</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">public</span> <span style="color: blue">double</span> Value</li>
 <li>&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">get</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">if</span> (_operation == <span style="color: blue">null</span>) _operation = _operationExecutor.GetOperation(_expression);</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">if</span> (_operation == <span style="color: blue">null</span>) <span style="color: blue">throw</span> <span style="color: blue">new</span> <span>NotSupportedException</span>(_expression);</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">return</span> _operation.Value;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;}</li>
 <li>&#160;&#160;&#160;&#160;}</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">public</span> <span style="color: blue">bool</span> HasValue</li>
 <li>&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">get</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">if</span> (_operation == <span style="color: blue">null</span>) _operation = _operationExecutor.GetOperation(_expression);</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">return</span> _operation != <span style="color: blue">null</span>;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;}</li>
 <li>&#160;&#160;&#160;&#160;}</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">#endregion</span></li>
 <li>}</li>
 </ol></div></div><br/>
2. IOperationExecutor, с помощью IOperationRecognizerProvider, будет проходить по различным распознавателям операций (IOperationRecognizer), находя нужные операции и выполняя их<br/>
3. В результате получаем либо число типа Double, либо исключение NotSupportedException с участком выражения, которое распознать не удалось.<br/>
<br/>
Для того, чтобы весь механизм запустить, нужно настроить объект IOperationRecognizerProvider и использовать его. Вот пример оъекта, который я создал для калькулятора:<br/>
<br/>
<div style="color: black; font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 3em; padding: 0 0 0 5px"><li><span style="color: blue">public</span> <span style="color: blue">class</span> <span>CalculatorOperationRecognizerProvider</span> : <span>IOperationRecognizerProvider</span></li>
 <li>{</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">#region</span> Implementation of IOperationRecognizerProvider</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: grey">///</span><span style="color: green"> </span><span style="color: grey">&lt;summary&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;<span style="color: grey">///</span><span style="color: green"> тут находятся рекогнайзеры операций в обратном порядке приоритета. </span></li>
 <li>&#160;&#160;&#160;&#160;<span style="color: grey">///</span><span style="color: green"> </span><span style="color: grey">&lt;/summary&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;<span style="color: grey">///</span><span style="color: green"> </span><span style="color: grey">&lt;returns&gt;&lt;/returns&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">public</span> <span>IEnumerable</span>&lt;<span>IEnumerable</span>&lt;<span>IOperationRecognizer</span>&gt;&gt; GetRecognizers()</li>
 <li>&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">return</span> <span style="color: blue">new</span> <span>List</span>&lt;<span>IEnumerable</span>&lt;<span>IOperationRecognizer</span>&gt;&gt;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>List</span>&lt;<span>IOperationRecognizer</span>&gt;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>BinaryOperationRecognizer</span>(</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span>&quot;+&quot;</span>, </li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>LambdaBinaryOperationProvider</span>((x, y) =&gt; x + y)),</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>BinaryOperationRecognizer</span>(</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span>&quot;-&quot;</span>, </li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>LambdaBinaryOperationProvider</span>((x, y) =&gt; x - y))</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;},</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>List</span>&lt;<span>IOperationRecognizer</span>&gt;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>BinaryOperationRecognizer</span>(</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span>&quot;*&quot;</span>,</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>LambdaBinaryOperationProvider</span>((x, y) =&gt; x*y)),</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>BinaryOperationRecognizer</span>(</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span>&quot;/&quot;</span>, </li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>LambdaBinaryOperationProvider</span>((x, y) =&gt; x/y)),</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;},</li>
 <li>&#160;</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>List</span>&lt;<span>IOperationRecognizer</span>&gt;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>BinaryOperationRecognizer</span>(</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span>&quot;^&quot;</span>, </li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>LambdaBinaryOperationProvider</span>(<span>Math</span>.Pow)),</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;},</li>
 <li>&#160;</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>List</span>&lt;<span>IOperationRecognizer</span>&gt;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>UnaryFunctionRecognizer</span>(</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span>&quot;sin&quot;</span>,</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>LambdaUnaryOperationProvider</span>(<span>Math</span>.Sin)),</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>UnaryFunctionRecognizer</span>(</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span>&quot;cos&quot;</span>, </li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>LambdaUnaryOperationProvider</span>(<span>Math</span>.Cos)),</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>UnaryFunctionRecognizer</span>(</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span>&quot;tan&quot;</span>, </li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>LambdaUnaryOperationProvider</span>(<span>Math</span>.Tan)),</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>UnaryFunctionRecognizer</span>(</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span>&quot;ctan&quot;</span>, </li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>LambdaUnaryOperationProvider</span>(x =&gt; 1/<span>Math</span>.Tan(x))),</li>
 <li>&#160;</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>UnaryFunctionRecognizer</span>(</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span>&quot;asin&quot;</span>, </li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>LambdaUnaryOperationProvider</span>(<span>Math</span>.Asin)),</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>UnaryFunctionRecognizer</span>(</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span>&quot;acos&quot;</span>, </li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>LambdaUnaryOperationProvider</span>(<span>Math</span>.Acos)),</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>UnaryFunctionRecognizer</span>(</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span>&quot;atan&quot;</span>, </li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>LambdaUnaryOperationProvider</span>(<span>Math</span>.Atan)),</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>UnaryFunctionRecognizer</span>(</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span>&quot;actan&quot;</span>, </li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>LambdaUnaryOperationProvider</span>(x =&gt; (<span>Math</span>.PI*0.5) - <span>Math</span>.Atan(x))),</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>UnaryFunctionRecognizer</span>(</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span>&quot;abs&quot;</span>, </li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>LambdaUnaryOperationProvider</span>(<span>Math</span>.Abs)),</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>UnaryFunctionRecognizer</span>(</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span>&quot;sqrt&quot;</span>, </li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>LambdaUnaryOperationProvider</span>(<span>Math</span>.Sqrt)),</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;},</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>List</span>&lt;<span>IOperationRecognizer</span>&gt;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>BracketsOperationRecognizer</span>(</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>LambdaUnaryOperationProvider</span>(x =&gt; x)),</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>AbsoluteBracketsOperationRecognizer</span>(</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>LambdaUnaryOperationProvider</span>(<span>Math</span>.Abs))</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;},</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>List</span>&lt;<span>IOperationRecognizer</span>&gt;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>ConstantRecognizer</span>(</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span>&quot;pi&quot;</span>, </li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span>Math</span>.PI, </li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>NumberOperationProvider</span>()),</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>ConstantRecognizer</span>(</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span>&quot;e&quot;</span>, </li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span>Math</span>.E, </li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>NumberOperationProvider</span>())</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;},</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>List</span>&lt;<span>IOperationRecognizer</span>&gt;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>NumberOperationRecognizer</span>(</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">new</span> <span>NumberOperationProvider</span>())</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;},</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;};</li>
 <li>&#160;&#160;&#160;&#160;}</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">#endregion</span></li>
 <li>}</li>
 </ol></div></div><br/>
В итоге я получил библиотеку разбора выражений, которую легко настроить или изменить логику всего лишь реализовав нужные интерфейсы. <br/>
<br/>
<div style="text-align: center">&#160;<b><span style="font-size: large">Часть 2. Калькулятор на Silverlight с использованием Mvvm</span></b></div><br/>
Сам по себе подход и использованием Mvvm подразумевает, что у нас будет Xaml страница, в качестве контекста данных для неё будет выступать специальный класс ViewModel, а изменения между этим классом и представлением будут синхронизированы посредством двухстороннего биндинга. В принципе, ничего сложного. <br/>
Итак, начем с конструирования ViewModel. Оговорюсь сразу, я использую библиотеку <!--noindex--><a href="http://mvvmlight.codeplex.com/" rel="nofollow">Galasoft.MvvmLight</a><!--/noindex-->, так как она позволяет довольно просто связать события контролов в представлении с командами в классе ViewModel.<br/>
Так как все команды, которые есть в калькуляторе, могут изменять состояние модели, я определил базовый класс для команды<br/>
<br/>
<div style="color: black; font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span style="color: blue">public</span> <span style="color: blue">abstract</span> <span style="color: blue">class</span> <span>CalculatorCommand</span> : <span>ICommand</span></li>
 <li>{</li>
 <li>&#160;&#160;&#160;&#160;&#160;<span style="color: blue">protected</span> <span>MainViewModel</span> _target;</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">protected</span> CalculatorCommand(<span>MainViewModel</span> target)</li>
 <li>&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;_target = target;</li>
 <li>&#160;&#160;&#160;&#160;}</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">public</span> <span style="color: blue">bool</span> CanExecute(<span style="color: blue">object</span> parameter)</li>
 <li>&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">return</span> _target != <span style="color: blue">null</span>;</li>
 <li>&#160;&#160;&#160;&#160;}</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">public</span> <span style="color: blue">abstract</span> <span style="color: blue">void</span> Execute(<span style="color: blue">object</span> parameter);</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">public</span> <span style="color: blue">event</span> <span>EventHandler</span> CanExecuteChanged;</li>
 <li>}</li>
 </ol></div></div><br/>
Далее, я разделил все команды на те, которые добавляют текст<br/>
<br/>
<div style="color: black; font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span style="color: blue">public</span> <span style="color: blue">class</span> <span>AddToTextCommand</span> : <span>CalculatorCommand</span></li>
 <li>{</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">public</span> AddToTextCommand(<span>MainViewModel</span> target) : <span style="color: blue">base</span>(target)</li>
 <li>&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</li>
 <li>&#160;&#160;&#160;&#160;}</li>
 <li>&#160;&#160;&#160;&#160;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">public</span> <span style="color: blue">override</span> <span style="color: blue">void</span> Execute(<span style="color: blue">object</span> parameter)</li>
 <li>&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">var</span> str = parameter <span style="color: blue">as</span> <span>String</span>;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">if</span> (!<span style="color: blue">string</span>.IsNullOrEmpty(str))</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;_target.CalculatorExpression += str;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;}</li>
 <li>&#160;&#160;&#160;&#160;}</li>
 <li>}</li>
 </ol></div></div><br/>
Очищают поле ввода<br/>
<br/>
<div style="color: black; font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span style="color: blue">public</span> <span style="color: blue">class</span> <span>ClearCommand</span> : <span>CalculatorCommand</span></li>
 <li>{</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">public</span> ClearCommand(<span>MainViewModel</span> target)</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;: <span style="color: blue">base</span>(target)</li>
 <li>&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</li>
 <li>&#160;&#160;&#160;&#160;}</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">public</span> <span style="color: blue">override</span> <span style="color: blue">void</span> Execute(<span style="color: blue">object</span> parameter)</li>
 <li>&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;_target.CalculatorExpression = <span style="color: blue">string</span>.Empty;</li>
 <li>&#160;&#160;&#160;&#160;}</li>
 <li>}</li>
 </ol></div></div><br/>
Убирают последний символ (если он есть)<br/>
<br/>
<div style="color: black; font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span style="color: blue">public</span> <span style="color: blue">class</span> <span>RemoveLastCharCommand</span> : <span>CalculatorCommand</span></li>
 <li>{</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">public</span> RemoveLastCharCommand(<span>MainViewModel</span> target) : <span style="color: blue">base</span>(target)</li>
 <li>&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</li>
 <li>&#160;&#160;&#160;&#160;}</li>
 <li>&#160;&#160;&#160;&#160;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">public</span> <span style="color: blue">override</span> <span style="color: blue">void</span> Execute(<span style="color: blue">object</span> parameter)</li>
 <li>&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">if</span> (!<span style="color: blue">string</span>.IsNullOrEmpty(_target.CalculatorExpression))</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;_target.CalculatorExpression = _target.CalculatorExpression.Substring(0, _target.CalculatorExpression.Length - 1);</li>
 <li>&#160;&#160;&#160;&#160;}</li>
 <li>}</li>
 </ol></div></div><br/>
И производят разбор и вычисление выражения<br/>
<br/>
<div style="color: black; font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span style="color: blue">public</span> <span style="color: blue">class</span> <span>ExecuteExpressionCommand</span>: <span>CalculatorCommand</span></li>
 <li>{</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">public</span> ExecuteExpressionCommand(<span>MainViewModel</span> target)</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;: <span style="color: blue">base</span>(target)</li>
 <li>&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</li>
 <li>&#160;&#160;&#160;&#160;}</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">public</span> <span style="color: blue">override</span> <span style="color: blue">void</span> Execute(<span style="color: blue">object</span> parameter)</li>
 <li>&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">try</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">var</span> oex = <span style="color: blue">new</span> <span>OperationExecutor</span>(<span style="color: blue">new</span> <span>CalculatorOperationRecognizerProvider</span>());</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">var</span> ex = <span>Expression</span>.Create(_target.CalculatorExpression, oex);</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;_target.CalculatorResult = <span>Math</span>.Round(ex.Value, 10).ToString(<span>CultureInfo</span>.InvariantCulture);</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;}</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">catch</span>(<span>Exception</span> ex)</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;_target.CalculatorResult = <span style="color: blue">string</span>.Format(<span>&quot;Expression '{</span><span style="color: mediumseagreen">0}</span><span>' not suported&quot;</span>, ex.Message);</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;}</li>
 <li>&#160;&#160;&#160;&#160;}</li>
 <li>}</li>
 </ol></div></div><br/>
Реалиация класса MainViewModel тривиальна<br/>
<br/>
<div style="color: black; font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span style="color: blue">public</span> <span style="color: blue">class</span> <span>MainViewModel</span> : <span>ViewModelBase</span></li>
 <li>{</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">public</span> MainViewModel()</li>
 <li>&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;AddToTextCommand = <span style="color: blue">new</span> <span>AddToTextCommand</span>(<span style="color: blue">this</span>);</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;RemoveLastCharCommand = <span style="color: blue">new</span> <span>RemoveLastCharCommand</span>(<span style="color: blue">this</span>);</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;ClearCommand = <span style="color: blue">new</span> <span>ClearCommand</span>(<span style="color: blue">this</span>);</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;ExecuteExpressionCommand = <span style="color: blue">new</span> <span>ExecuteExpressionCommand</span>(<span style="color: blue">this</span>);</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;CalculatorResult = <span>&quot; &quot;</span>;</li>
 <li>&#160;&#160;&#160;&#160;}</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">public</span> <span>ICommand</span> AddToTextCommand { <span style="color: blue">get</span>; <span style="color: blue">set</span>; }</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">public</span> <span>ICommand</span> RemoveLastCharCommand { <span style="color: blue">get</span>; <span style="color: blue">set</span>; }</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">public</span> <span>ICommand</span> ClearCommand { <span style="color: blue">get</span>; <span style="color: blue">set</span>; }</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">public</span> <span>ICommand</span> ExecuteExpressionCommand { <span style="color: blue">get</span>; <span style="color: blue">set</span>; }</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">private</span> <span style="color: blue">string</span> _calculatorExpression;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">public</span> <span style="color: blue">string</span> CalculatorExpression</li>
 <li>&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">get</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">return</span> _calculatorExpression;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;}</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">set</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">if</span> (_calculatorExpression != <span style="color: blue">value</span>)</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;_calculatorExpression = <span style="color: blue">value</span>;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;RaisePropertyChanged(<span>&quot;CalculatorExpression&quot;</span>);</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;}</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;}</li>
 <li>&#160;&#160;&#160;&#160;}</li>
 <li>&#160;</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">private</span> <span style="color: blue">string</span> _calculatorResult;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">public</span> <span style="color: blue">string</span> CalculatorResult</li>
 <li>&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">get</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">return</span> _calculatorResult;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;}</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">set</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">if</span> (_calculatorResult != <span style="color: blue">value</span>)</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;_calculatorResult = <span style="color: blue">value</span>;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;RaisePropertyChanged(<span>&quot;CalculatorResult&quot;</span>);</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;}</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;}</li>
 <li>&#160;&#160;&#160;&#160;}</li>
 <li>}</li>
 </ol></div></div><br/>
Осталось только разработать страницу, на которой всё это будет отображаться. Нет смысла приводить тут весь её код, покажу только основные моменты:<br/>
<br/>
1. Использоваие статических ресурсов заложено в шаблоне приложения, и это хорошо, так как при разных темах значения этих ресурсов может изменяться:<br/>
<br/>
<div style="color: black; font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2em; padding: 0 0 0 5px"><li><span style="color: red">FontFamily</span><span style="color: blue">=&quot;{</span><span>StaticResource</span><span style="color: red"> PhoneFontFamilyNormal}</span><span style="color: blue">&quot;</span></li>
 <li><span style="color: red">FontSize</span><span style="color: blue">=&quot;{</span><span>StaticResource</span><span style="color: red"> PhoneFontSizeNormal}</span><span style="color: blue">&quot;</span></li>
 <li><span style="color: red">Foreground</span><span style="color: blue">=&quot;{</span><span>StaticResource</span><span style="color: red"> PhoneForegroundBrush}</span><span style="color: blue">&quot;</span></li>
 </ol></div></div><br/>
Теперь, если пользователь изменит тему с тёмной на светлую, то приложение легко к этому подстроится<br/>
<br/>
<div style="text-align: center"><!--noindex--><a href="http://3.bp.blogspot.com/-yW3bJI0q70c/TwGxr1Fs7JI/AAAAAAAAC54/OW2suQL9VxE/s1600/s3.png" rel="nofollow" style="margin-left: 1em; margin-right: 1em"><img src="http://3.bp.blogspot.com/-yW3bJI0q70c/TwGxr1Fs7JI/AAAAAAAAC54/OW2suQL9VxE/s400/s3.png" width="240px" height="400px" border="0"/></a><!--/noindex--></div><br/>
2. Контрол Panorama я разместил под текстбоксом. Это позволяет перелистывать страницы не теряя текстбокс из виду.<br/>
3. Привязка команд к событиям происходит декларативно, благодаря библиотеке <!--noindex--><a href="http://mvvmlight.codeplex.com/" rel="nofollow">Galasoft.MvvmLight</a><!--/noindex--><br/>
<br/>
<div style="color: black; font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 3em; padding: 0 0 0 5px"><li><span style="color: blue">&lt;</span><span>Button</span><span style="color: red"> Content</span><span style="color: blue">=&quot;+&quot;</span><span style="color: red"> Grid.Row</span><span style="color: blue">=&quot;4&quot;</span><span style="color: red"> Grid.Column</span><span style="color: blue">=&quot;3&quot; &gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>i</span><span style="color: blue">:</span><span>Interaction.Triggers</span><span style="color: blue">&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>i</span><span style="color: blue">:</span><span>EventTrigger</span><span style="color: red"> EventName</span><span style="color: blue">=&quot;Click&quot;&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>Command</span><span style="color: blue">:</span><span>EventToCommand</span><span style="color: red"> Command</span><span style="color: blue">=&quot;{</span><span>Binding</span><span style="color: red"> AddToTextCommand</span><span style="color: blue">,</span><span style="color: red"> Mode</span><span style="color: blue">=OneWay}&quot;</span><span style="color: red"> CommandParameter</span><span style="color: blue">=&quot;+&quot; /&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;/</span><span>i</span><span style="color: blue">:</span><span>EventTrigger</span><span style="color: blue">&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;/</span><span>i</span><span style="color: blue">:</span><span>Interaction.Triggers</span><span style="color: blue">&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;/</span><span>Button</span><span style="color: blue">&gt;</span></li>
 </ol></div></div>4. Ну, и последнее. При смене ориантации телефона мне хотелось увидеть анимацию перехода страницы из одного состояния в другое. Этого я добился с помощью библиотеки <!--noindex--><a href="http://silverlight.codeplex.com/" rel="nofollow">Silverlight Toolkit</a><!--/noindex--><br/>
<br/>
<div style="color: black; font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span style="color: blue">public</span> <span style="color: blue">partial</span> <span style="color: blue">class</span> <span>MainPage</span> : <span>PhoneApplicationPage</span></li>
 <li>{</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">private</span> <span style="color: blue">readonly</span> <span>MainViewModel</span> _mainViewModel;</li>
 <li>&#160;&#160;&#160;&#160;<span>PageOrientation</span> _lastOrientation;</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: green">// Constructor</span></li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">public</span> MainPage()</li>
 <li>&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;InitializeComponent();</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">var</span> locator = <span style="color: blue">new</span> <span>ViewModelLocator</span>();</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;_mainViewModel = locator.Main;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;DataContext = _mainViewModel;</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;OrientationChanged += MainPageOrientationChanged;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;_lastOrientation = Orientation;</li>
 <li>&#160;&#160;&#160;&#160;}</li>
 <li>&#160;&#160;&#160;&#160;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">void</span> MainPageOrientationChanged(<span style="color: blue">object</span> sender, <span>OrientationChangedEventArgs</span> e)</li>
 <li>&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">var</span> newOrientation = e.Orientation;</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">var</span> transitionElement = <span style="color: blue">new</span> <span>RotateTransition</span>();</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">switch</span> (newOrientation)</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">case</span> <span>PageOrientation</span>.Landscape:</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">case</span> <span>PageOrientation</span>.LandscapeRight:</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;transitionElement.Mode = _lastOrientation == <span>PageOrientation</span>.PortraitUp ? <span>RotateTransitionMode</span>.In90Counterclockwise : <span>RotateTransitionMode</span>.In180Clockwise;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">break</span>;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">case</span> <span>PageOrientation</span>.LandscapeLeft:</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;transitionElement.Mode = _lastOrientation == <span>PageOrientation</span>.LandscapeRight ? <span>RotateTransitionMode</span>.In180Counterclockwise : <span>RotateTransitionMode</span>.In90Clockwise;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">break</span>;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">case</span> <span>PageOrientation</span>.Portrait:</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">case</span> <span>PageOrientation</span>.PortraitUp:</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;transitionElement.Mode = _lastOrientation == <span>PageOrientation</span>.LandscapeLeft ? <span>RotateTransitionMode</span>.In90Counterclockwise : <span>RotateTransitionMode</span>.In90Clockwise;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">break</span>;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">default</span>:</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">break</span>;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;}</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">var</span> phoneApplicationPage = (<span>PhoneApplicationPage</span>)(((<span>PhoneApplicationFrame</span>)<span>Application</span>.Current.RootVisual)).Content;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">var</span> transition = transitionElement.GetTransition(phoneApplicationPage);</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;transition.Completed += <span style="color: blue">delegate</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;transition.Stop();</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;};</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;transition.Begin();</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;_lastOrientation = newOrientation;</li>
 <li>&#160;&#160;&#160;&#160;}</li>
 <li>}</li>
 </ol></div></div><br/>
На этом закончена основная работа над калькулятором. Оставалось только навести красоту, да прикрутить иконку (которую я снова взял среди <!--noindex--><a href="http://findicons.com/icon/177376/calculator" rel="nofollow">бесплатных</a><!--/noindex-->). Я назвал проект Calculon и выложил его на <!--noindex--><a href="http://calculon.codeplex.com/" rel="nofollow">кодеплекс</a><!--/noindex-->, так что вы легко можете скачать исходники и поиграть с кодом. Также я отправил работу в маркет, приложение сделал, естественно, бесплатным.<br/>
<br/>
В итоге я получил калькулятор, работающий на Windows Phone 7. Учитывая, что моей специализацией является Web разработка, и что я не профессионал в Silverlight, возможность так легко написать готовое приложения для мобильного телефона говорит о низком пороге вхождения в технологию. <br/>
<br/>
Результат работы:<br/>
<div style="text-align: center"><!--noindex--><a href="http://2.bp.blogspot.com/-Z3838lunOR0/TwG2wCtyKUI/AAAAAAAAC6E/ZlrnG64viTU/s1600/s5.png" rel="nofollow" style="margin-left: 1em; margin-right: 1em"><img src="http://2.bp.blogspot.com/-Z3838lunOR0/TwG2wCtyKUI/AAAAAAAAC6E/ZlrnG64viTU/s640/s5.png" width="640px" height="352px" border="0"/></a><!--/noindex--></div><br/>
На этом всё. Всем спасибо.<br/>
</div><div><img src="https://blogger.googleusercontent.com/tracker/8897990838383834685-8445317878168206426?l=tym32167.blogspot.com" width="1px" height="1px" border="0"/></div>]]></description>
      <category><![CDATA[Windows Phone]]></category>
      <category><![CDATA[.NET]]></category>
      <category><![CDATA[Expressions]]></category>
      <category><![CDATA[C#]]></category>
      <category><![CDATA[Silverlight]]></category>
      <guid>http://tym32167.blogspot.com/2012/01/silverlight-windows-phone-7.html</guid>
      <pubDate>Mon, 02 Jan 2012 14:01:00 UT</pubDate>
      <dc:creator><![CDATA[tym32167]]></dc:creator>
    </item>
    <item>
      <title><![CDATA[.NET Notepad идет в массы!]]></title>
      <link>http://microgeek.ru/blogs/tym32167/1714/</link>
      <description><![CDATA[<div style="text-align: left">Здравствуйте. Сегодня мне пришло весьма интересное письмо:<br/>
<table class="blog-quote"><tr><th>Цитата</th></tr><tr><td>Congratulations,<br/>
<br/>
.NET Notepad, one of your products, has been added to Softpedia's database<br/>
of software programs for the Windows operating system. It is featured with<br/>
a description text, screenshots, download links and technical details on<br/>
this page:<br/>
<!--noindex--><a href="http://www.softpedia.com/get/Office-tools/Text-editors/NET-Notepad.shtml" rel="nofollow">http://www.softpedia.com/get/Office-tools/Text-editors/NET-Notepad.shtml</a><!--/noindex--><br/>
<br/>
The description text was created by our editors, using sources such as text<br/>
from your product's homepage, information from its help system, the PAD<br/>
file (if available) and the editor's own opinions on the program itself.<br/>
<br/>
<br/>
&quot;.NET Notepad&quot; has been tested in the Softpedia labs using several<br/>
industry-leading security solutions and found to be completely clean of<br/>
adware/spyware components. We are impressed with the quality of your<br/>
product and encourage you to keep these high standards in the future.<br/>
<br/>
To assure our visitors that .NET Notepad is clean, we have granted it with<br/>
the &quot;100% FREE&quot; Softpedia award. To let your users know about this<br/>
certification, you may display this award on your website, on software<br/>
boxes or inside your product...</td></tr></table><a name="more" rel="nofollow"></a><br/>
Я даже немного растерялся. Неужели румынский сайт <!--noindex--><a href="http://ru.wikipedia.org/wiki/Softpedia" rel="nofollow">Softpedia</a><!--/noindex-->, который занимает 356 место по посещаемости в мире, обратил внимание на мою скромную программу <!--noindex--><a href="http://dotnetnotepad.codeplex.com/" rel="nofollow">.NET Notepad</a><!--/noindex-->, процесс создания которой я уже <!--noindex--><a href="http://tym32167.blogspot.com/2011/12/avalonedit-avalondock.html" rel="nofollow">описывал</a><!--/noindex--> в своём блоге несколько дней назад? Оказалось правда. Мою программу можно поглядеть <!--noindex--><a href="http://www.softpedia.com/get/Office-tools/Text-editors/NET-Notepad.shtml" rel="nofollow">тут</a><!--/noindex-->. <br/>
Ещё ссылки:<br/>
Награда &quot;100% FREE&quot;<br/>
<!--noindex--><a title="100% FREE Certified by Softpedia" href="http://www.softpedia.com/progClean/NET-Notepad-Clean-203062.html" rel="nofollow"><img src="http://s1.softpedia-static.com/base_img/softpedia_free_award_f.gif" width="170px" height="116px" border="0"/></a><!--/noindex--><br/>
Ссылка на страницу описания<br/>
<!--noindex--><a href="http://www.softpedia.com/get/Office-tools/Text-editors/NET-Notepad.shtml" rel="nofollow"><img src="http://www.softpedia.com/images/softpedia_download_small.gif" border="0"/></a><!--/noindex--><br/>
</div><div><img src="https://blogger.googleusercontent.com/tracker/8897990838383834685-788647410563157605?l=tym32167.blogspot.com" width="1px" height="1px" border="0"/></div>]]></description>
      <category><![CDATA[.NET Notepad]]></category>
      <category><![CDATA[Softpedia]]></category>
      <category><![CDATA[C#]]></category>
      <guid>http://tym32167.blogspot.com/2011/12/net-notepad.html</guid>
      <pubDate>Mon, 26 Dec 2011 17:00:00 UT</pubDate>
      <dc:creator><![CDATA[tym32167]]></dc:creator>
    </item>
    <item>
      <title><![CDATA[Реализация поведения контролов в Silverlight]]></title>
      <link>http://microgeek.ru/blogs/tym32167/1713/</link>
      <description><![CDATA[<div style="text-align: left">Здравствуйте. Сегодня поговорим о том, как определять поведение для различных контролов в Silverlight. Начнем с простого перетаскивания по канвасу. Задача, в принципе, очень простая, и даже просто погуглив можно найти нужное решение (например, <!--noindex--><a href="http://msdn.microsoft.com/en-us/library/cc189066(v=vs.95).aspx" rel="nofollow">раз</a><!--/noindex--> и <!--noindex--><a href="http://jesseliberty.com/2011/02/11/reactive-drag-and-drop-part-1/" rel="nofollow">два</a><!--/noindex-->), но я хочу сделать это решение чуть более универсальным. <br/>
Итак, в основе перетаскивания лежит использование 3х событий: MouseLeftButtonDown, MouseLeftButtonUp и MouseMove. <br/>
<a name="more" rel="nofollow"></a><br/>
Для примера, я возьму код из <!--noindex--><a href="http://msdn.microsoft.com/en-us/library/cc189066(v=vs.95).aspx" rel="nofollow">MSDN</a><!--/noindex-->.<br/>
<br/>
<div style="color: black; font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span style="color: blue">&lt;</span><span>UserControl</span><span style="color: red"> x</span><span style="color: blue">:</span><span style="color: red">Class</span><span style="color: blue">=&quot;DragAndDropSimple.Page&quot;</span></li>
 <li>&#160;&#160;&#160;<span style="color: red"> xmlns</span><span style="color: blue">=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;</span> </li>
 <li>&#160;&#160;&#160;<span style="color: red"> xmlns</span><span style="color: blue">:</span><span style="color: red">x</span><span style="color: blue">=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;</span> </li>
 <li>&#160;&#160;&#160;<span style="color: red"> Width</span><span style="color: blue">=&quot;400&quot;</span><span style="color: red"> Height</span><span style="color: blue">=&quot;300&quot;&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>Canvas</span><span style="color: red"> x</span><span style="color: blue">:</span><span style="color: red">Name</span><span style="color: blue">=&quot;rootCanvas&quot;</span></li>
 <li> <span style="color: red"> Width</span><span style="color: blue">=&quot;640&quot;</span></li>
 <li> <span style="color: red"> Height</span><span style="color: blue">=&quot;480&quot;</span></li>
 <li> <span style="color: red"> Background</span><span style="color: blue">=&quot;Gray&quot;</span></li>
 <li> <span style="color: blue"> &gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: green">&lt;!-- You can drag this rectangle around the canvas. --&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>Rectangle</span></li>
 <li>&#160;&#160;&#160;<span style="color: red"> MouseLeftButtonDown</span><span style="color: blue">=&quot;</span><span style="color: red">Handle_MouseDown</span><span style="color: blue">&quot;</span></li>
 <li>&#160;&#160;&#160;<span style="color: red"> MouseMove</span><span style="color: blue">=&quot;</span><span style="color: red">Handle_MouseMove</span><span style="color: blue">&quot;</span></li>
 <li>&#160;&#160;&#160;<span style="color: red"> MouseLeftButtonUp</span><span style="color: blue">=&quot;</span><span style="color: red">Handle_MouseUp</span><span style="color: blue">&quot;</span></li>
 <li>&#160;&#160;&#160;<span style="color: red"> Canvas.Left</span><span style="color: blue">=&quot;30&quot;</span><span style="color: red"> Canvas.Top</span><span style="color: blue">=&quot;30&quot;</span><span style="color: red"> Fill</span><span style="color: blue">=&quot;Red&quot;</span></li>
 <li>&#160;&#160;&#160;<span style="color: red"> Width</span><span style="color: blue">=&quot;50&quot;</span><span style="color: red"> Height</span><span style="color: blue">=&quot;50&quot; /&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">&lt;/</span><span>Canvas</span><span style="color: blue">&gt;</span></li>
 <li>&#160;</li>
 <li><span style="color: blue">&lt;/</span><span>UserControl</span><span style="color: blue">&gt;</span></li>
 </ol></div></div><br/>
<div style="color: black; font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span style="color: green">// Global variables used to keep track of the </span></li>
 <li><span style="color: green">// mouse position and whether the object is captured</span></li>
 <li><span style="color: green">// by the mouse.</span></li>
 <li><span style="color: blue">bool</span> isMouseCaptured;</li>
 <li><span style="color: blue">double</span> mouseVerticalPosition;</li>
 <li><span style="color: blue">double</span> mouseHorizontalPosition;</li>
 <li>&#160;</li>
 <li><span style="color: blue">public</span> <span style="color: blue">void</span> Handle_MouseDown(<span style="color: blue">object</span> sender, <span>MouseEventArgs</span> args)</li>
 <li>{</li>
 <li>&#160;&#160;&#160;&#160;<span>Rectangle</span> item = sender <span style="color: blue">as</span> <span>Rectangle</span>;</li>
 <li>&#160;&#160;&#160;&#160;mouseVerticalPosition = args.GetPosition(<span style="color: blue">null</span>).Y;</li>
 <li>&#160;&#160;&#160;&#160;mouseHorizontalPosition = args.GetPosition(<span style="color: blue">null</span>).X;</li>
 <li>&#160;&#160;&#160;&#160;isMouseCaptured = <span style="color: blue">true</span>;</li>
 <li>&#160;&#160;&#160;&#160;item.CaptureMouse();</li>
 <li>}</li>
 <li>&#160;</li>
 <li><span style="color: blue">public</span> <span style="color: blue">void</span> Handle_MouseMove(<span style="color: blue">object</span> sender, <span>MouseEventArgs</span> args)</li>
 <li>{</li>
 <li>&#160;&#160;&#160;&#160;<span>Rectangle</span> item = sender <span style="color: blue">as</span> <span>Rectangle</span>;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">if</span> (isMouseCaptured)</li>
 <li>&#160;&#160;&#160;&#160;{</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: green">// Calculate the current position of the object.</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">double</span> deltaV = args.GetPosition(<span style="color: blue">null</span>).Y - mouseVerticalPosition;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">double</span> deltaH = args.GetPosition(<span style="color: blue">null</span>).X - mouseHorizontalPosition;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">double</span> newTop = deltaV + (<span style="color: blue">double</span>)item.GetValue(<span>Canvas</span>.TopProperty);</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">double</span> newLeft = deltaH + (<span style="color: blue">double</span>)item.GetValue(<span>Canvas</span>.LeftProperty);</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: green">// Set new position of object.</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;item.SetValue(<span>Canvas</span>.TopProperty, newTop);</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;item.SetValue(<span>Canvas</span>.LeftProperty, newLeft);</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: green">// Update position global variables.</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;mouseVerticalPosition = args.GetPosition(<span style="color: blue">null</span>).Y;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;mouseHorizontalPosition = args.GetPosition(<span style="color: blue">null</span>).X;</li>
 <li>&#160;&#160;&#160;&#160;}</li>
 <li>}</li>
 <li>&#160;</li>
 <li><span style="color: blue">public</span> <span style="color: blue">void</span> Handle_MouseUp(<span style="color: blue">object</span> sender, <span>MouseEventArgs</span> args)</li>
 <li>{</li>
 <li>&#160;&#160;&#160;&#160;<span>Rectangle</span> item = sender <span style="color: blue">as</span> <span>Rectangle</span>;</li>
 <li>&#160;&#160;&#160;&#160;isMouseCaptured = <span style="color: blue">false</span>;</li>
 <li>&#160;&#160;&#160;&#160;item.ReleaseMouseCapture();</li>
 <li>&#160;&#160;&#160;&#160;mouseVerticalPosition = -1;</li>
 <li>&#160;&#160;&#160;&#160;mouseHorizontalPosition = -1;</li>
 <li>}</li>
 </ol></div></div><br/>
Вот и всё стало ясно. Суть в том, чтобы максимально упростить добавление возможности перетаскивания для контрола. <br/>
Теперь определимся - перетаскивание, по сути, характеристика контрола, или же его поведение (трактовать можно по разному). Поэтому я для начала решил написать простой интерфейс:<br/>
<br/>
<div style="color: black; font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span style="color: grey">///</span><span style="color: green"> </span><span style="color: grey">&lt;summary&gt;</span></li>
 <li><span style="color: grey">///</span><span style="color: green"> Определяет интерфейс объекта, который представляет собой поведение</span></li>
 <li><span style="color: grey">///</span><span style="color: green"> </span><span style="color: grey">&lt;/summary&gt;</span></li>
 <li><span style="color: grey">///</span><span style="color: green"> </span><span style="color: grey">&lt;typeparam name=&quot;T&quot;&gt;&lt;/typeparam&gt;</span></li>
 <li><span style="color: blue">public</span> <span style="color: blue">interface</span> <span>IBehavior</span>&lt;<span style="color: blue">in</span> T&gt; <span style="color: blue">where</span> T:<span>UIElement</span></li>
 <li>{</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">void</span> SetTarget(T target);</li>
 <li>}</li>
 </ol></div></div><br/>
Я выбрал UIElement потому, что с него начинается поддержка нужных нам событий мышки. <br/>
<br/>
<div style="color: black; font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span style="color: blue">namespace</span> System.Windows</li>
 <li>{</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">public</span> <span style="color: blue">abstract</span> <span style="color: blue">class</span> <span>UIElement</span> : <span>DependencyObject</span>, <span style="color: red">IAutomationElement</span></li>
 <li>&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">public</span> <span style="color: blue">static</span> <span style="color: blue">readonly</span> <span>RoutedEvent</span> MouseLeftButtonDownEvent = <span style="color: blue">new</span> <span>RoutedEvent</span>(<span>&quot;UIElement.MouseLeftButtonDown&quot;</span>);</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">public</span> <span style="color: blue">static</span> <span style="color: blue">readonly</span> <span>RoutedEvent</span> MouseLeftButtonUpEvent = <span style="color: blue">new</span> <span>RoutedEvent</span>(<span>&quot;UIElement.MouseLeftButtonUp&quot;</span>);</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">public</span> <span style="color: blue">static</span> <span style="color: blue">readonly</span> <span>RoutedEvent</span> MouseRightButtonDownEvent = <span style="color: blue">new</span> <span>RoutedEvent</span>(<span>&quot;UIElement.MouseRightButtonDown&quot;</span>);</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">public</span> <span style="color: blue">static</span> <span style="color: blue">readonly</span> <span>RoutedEvent</span> MouseRightButtonUpEvent = <span style="color: blue">new</span> <span>RoutedEvent</span>(<span>&quot;UIElement.MouseRightButtonUp&quot;</span>);</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">public</span> <span style="color: blue">static</span> <span style="color: blue">readonly</span> <span>RoutedEvent</span> MouseWheelEvent = <span style="color: blue">new</span> <span>RoutedEvent</span>(<span>&quot;UIElement.MouseWheel&quot;</span>);</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;.......</li>
 </ol></div></div><br/>
Теперь механизм перетаскивания, как я его вижу:<br/>
<br/>
1. Пользователь нажимает на объект <br/>
- запоминаем его Z-индекс, прозрачность и курсор мышки<br/>
- Меняем Z-индекс на какой нибудь большой, меняем прозрачность, меняем курсор <br/>
- Захватываем мышку <br/>
<br/>
2. Пользователь двигает мышку<br/>
- Вычисляем сдвиг мышки и двигаем объект<br/>
<br/>
3. Пользователь отпускает кнопку мышки<br/>
- восстанавливаем курсор, прозрачнсть и Z-индекс<br/>
<br/>
Вот класс, реализующий нужный мне функционал<br/>
<br/>
<br/>
<div style="color: black; font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 3em; padding: 0 0 0 5px"><li><span style="color: grey">///</span><span style="color: green"> </span><span style="color: grey">&lt;summary&gt;</span></li>
 <li><span style="color: grey">///</span><span style="color: green"> Использую FrameworkElement, так как курсор, z-индекс, прозрачность доступны только с этого класса</span></li>
 <li><span style="color: grey">///</span><span style="color: green"> </span><span style="color: grey">&lt;/summary&gt;</span></li>
 <li><span style="color: grey">///</span><span style="color: green"> </span><span style="color: grey">&lt;typeparam name=&quot;T&quot;&gt;&lt;/typeparam&gt;</span></li>
 <li><span style="color: blue">public</span> <span style="color: blue">class</span> <span>DragBehavior</span>&lt;T&gt; : <span>IBehavior</span>&lt;T&gt; <span style="color: blue">where</span> T : <span>FrameworkElement</span></li>
 <li>{</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">private</span> T _target;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">private</span> <span style="color: blue">bool</span> _isDrag;</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: grey">///</span><span style="color: green"> </span><span style="color: grey">&lt;summary&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;<span style="color: grey">///</span><span style="color: green"> предыдущее состояние положения курсора и z-индекса</span></li>
 <li>&#160;&#160;&#160;&#160;<span style="color: grey">///</span><span style="color: green"> </span><span style="color: grey">&lt;/summary&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">private</span> <span>Point</span> _mousePrevious;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">private</span> <span style="color: blue">int</span> _oldZIndex;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">private</span> <span style="color: blue">double</span> _opacity;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">private</span> <span>Cursor</span> _cursor;</li>
 <li>&#160;&#160;&#160;&#160;</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: grey">///</span><span style="color: green"> </span><span style="color: grey">&lt;summary&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;<span style="color: grey">///</span><span style="color: green"> Событие нажатия левой кнопки мыши</span></li>
 <li>&#160;&#160;&#160;&#160;<span style="color: grey">///</span><span style="color: green"> </span><span style="color: grey">&lt;/summary&gt;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</span></li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">protected</span> <span style="color: blue">virtual</span> <span style="color: blue">void</span> RecMouseLeftButtonDown(<span style="color: blue">object</span> sender, <span>MouseButtonEventArgs</span> e)</li>
 <li>&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">if</span> (_target == <span style="color: blue">null</span>) <span style="color: blue">return</span>;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: green">// не пускать вобытие вверх по дереву</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;e.Handled = <span style="color: blue">true</span>;</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: green">// сохранение информации о состоянии объекта</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;_mousePrevious = e.GetPosition(_target);</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;_cursor = _target.Cursor;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;_oldZIndex = <span>Canvas</span>.GetZIndex(_target);</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;_opacity = _target.Opacity;</li>
 <li>&#160;</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;_target.CaptureMouse();</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;_target.Opacity = 0.8;</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: green">// Вывод объекта на передний план</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span>Canvas</span>.SetZIndex(_target, 10000);</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: green">// Курсор мыши</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;_target.Cursor = <span>Cursors</span>.Hand;</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;_isDrag = <span style="color: blue">true</span>;</li>
 <li>&#160;&#160;&#160;&#160;}</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: grey">///</span><span style="color: green"> </span><span style="color: grey">&lt;summary&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;<span style="color: grey">///</span><span style="color: green"> Отпускание кнопки мыши</span></li>
 <li>&#160;&#160;&#160;&#160;<span style="color: grey">///</span><span style="color: green"> </span><span style="color: grey">&lt;/summary&gt;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</span></li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">protected</span> <span style="color: blue">virtual</span> <span style="color: blue">void</span> RecMouseLeftButtonUp(<span style="color: blue">object</span> sender, <span>MouseButtonEventArgs</span> e)</li>
 <li>&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">if</span> (_target == <span style="color: blue">null</span>) <span style="color: blue">return</span>;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: green">// не пускать вобытие вверх по дереву</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;e.Handled = <span style="color: blue">true</span>;</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: green">// Восстановление z-индекса и состояния объекта</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span>Canvas</span>.SetZIndex(_target, _oldZIndex);</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;_target.ReleaseMouseCapture();</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;_target.Opacity = _opacity;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;_target.Cursor = _cursor;</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;_isDrag = <span style="color: blue">false</span>;</li>
 <li>&#160;&#160;&#160;&#160;}</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: grey">///</span><span style="color: green"> </span><span style="color: grey">&lt;summary&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;<span style="color: grey">///</span><span style="color: green"> Событие движения мыши</span></li>
 <li>&#160;&#160;&#160;&#160;<span style="color: grey">///</span><span style="color: green"> </span><span style="color: grey">&lt;/summary&gt;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</span></li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">protected</span> <span style="color: blue">virtual</span> <span style="color: blue">void</span> RecMouseMove(<span style="color: blue">object</span> sender, <span>MouseEventArgs</span> e)</li>
 <li>&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">if</span> (_target == <span style="color: blue">null</span>) <span style="color: blue">return</span>;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">if</span> (_isDrag)</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: green">// получаем новую позицию объекта (не важно в каких координатах) </span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: green">// это нужно только для подсчёта смещения</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">var</span> p = e.GetPosition(_target);</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: green">// получаем смещение объекта</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">var</span> dx = p.X - _mousePrevious.X;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">var</span> dy = p.Y - _mousePrevious.Y;</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;MoveElement(_target, dx, dy);</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;}</li>
 <li>&#160;&#160;&#160;&#160;}</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">private</span> <span style="color: blue">void</span> MoveElement(T target, <span style="color: blue">double</span> dx, <span style="color: blue">double</span> dy)</li>
 <li>&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">var</span> x = <span>Canvas</span>.GetLeft(_target) + dx;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">var</span> y = <span>Canvas</span>.GetTop(_target) + dy;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span>Canvas</span>.SetLeft(target, x);</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span>Canvas</span>.SetTop(target, y);</li>
 <li>&#160;&#160;&#160;&#160;}</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">public</span> <span style="color: blue">void</span> SetTarget(T target)</li>
 <li>&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">if</span> (_target != <span style="color: blue">null</span>)</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;_target.MouseLeftButtonDown -= RecMouseLeftButtonDown;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;_target.MouseLeftButtonUp -= RecMouseLeftButtonUp;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;_target.MouseMove -= RecMouseMove;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;}</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;_target = target;</li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">if</span> (target != <span style="color: blue">null</span>)</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;_target.MouseLeftButtonDown += RecMouseLeftButtonDown;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;_target.MouseLeftButtonUp += RecMouseLeftButtonUp;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;_target.MouseMove += RecMouseMove;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;}</li>
 <li>&#160;&#160;&#160;&#160;}</li>
 <li>}</li>
 </ol></div></div>Пора применить этот класс в деле! <br/>
Я разместил на главной и единственной странице проекта один канвас. По нему мы будем двигать объекты.<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>&lt;</span><span>UserControl</span><span> x</span><span>:</span><span>Class</span><span>=&quot;SilverlightApplication1.MainPage&quot;</span></li>
 <li> <span> xmlns</span><span>=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;</span></li>
 <li> <span> xmlns</span><span>:</span><span>x</span><span>=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;</span></li>
 <li> <span> xmlns</span><span>:</span><span>d</span><span>=&quot;http://schemas.microsoft.com/expression/blend/2008&quot;</span></li>
 <li> <span> xmlns</span><span>:</span><span>mc</span><span>=&quot;http://schemas.openxmlformats.org/markup-compatibility/2006&quot;</span></li>
 <li> <span> mc</span><span>:</span><span>Ignorable</span><span>=&quot;d&quot;</span></li>
 <li> <span> d</span><span>:</span><span>DesignHeight</span><span>=&quot;500&quot;</span><span> d</span><span>:</span><span>DesignWidth</span><span>=&quot;500&quot;&gt;</span></li>
 <li> <span>&lt;</span><span>Grid</span><span> x</span><span>:</span><span>Name</span><span>=&quot;LayoutRoot&quot;</span><span> Background</span><span>=&quot;Gray&quot;&gt;</span></li>
 <li> <span>&lt;</span><span>Canvas</span><span> Grid.Column</span><span>=&quot;1&quot;</span><span> Background</span><span>=&quot;White&quot;</span><span> Margin</span><span>=&quot;10&quot;</span><span> x</span><span>:</span><span>Name</span><span>=&quot;canvas&quot;&gt; </span></li>
 <li> <span>&lt;/</span><span>Canvas</span><span>&gt;</span></li>
 <li> <span>&lt;/</span><span>Grid</span><span>&gt;</span></li>
 <li><span>&lt;/</span><span>UserControl</span><span>&gt;</span></li>
 </ol></div></div>В коде я этот канвас заполняю прямоугольниками и придаю им поведение<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>public</span> <span>partial</span> <span>class</span> <span>MainPage</span> : <span>UserControl</span></li>
 <li>{</li>
 <li> <span>public</span> MainPage()</li>
 <li> {</li>
 <li> InitializeComponent();</li>
 <li> Init();</li>
 <li> InitBehaviors();</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li> <span>///</span><span> Функция, заполняет канвас случайным образм прямоугольниками разных размеров и цветов</span></li>
 <li> <span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li> <span>void</span> Init()</li>
 <li> {</li>
 <li> <span>var</span> rand = <span>new</span> <span>Random</span>(<span>DateTime</span>.Now.Millisecond);</li>
 <li>&#160;</li>
 <li> <span>for</span> (<span>int</span> i = 0; i &lt; 100; i++)</li>
 <li> {</li>
 <li> <span>var</span> x = rand.NextDouble() * 300;</li>
 <li> <span>var</span> y = rand.NextDouble() * 300;</li>
 <li>&#160;</li>
 <li> <span>var</span> a = 255;</li>
 <li> <span>var</span> r = rand.Next(255);</li>
 <li> <span>var</span> g = rand.Next(255);</li>
 <li> <span>var</span> b = rand.Next(255);</li>
 <li>&#160;</li>
 <li> <span>var</span> color = <span>new</span> <span>Color</span> {A = (<span>byte</span>)a, R = (<span>byte</span>)r, G = (<span>byte</span>)g, B = (<span>byte</span>)b};</li>
 <li>&#160;</li>
 <li> <span>var</span> rect = <span>new</span> <span>Rectangle</span> {Fill = <span>new</span> <span>SolidColorBrush</span>(color), Width = r, Height = b};</li>
 <li> canvas.Children.Add(rect);</li>
 <li>&#160;</li>
 <li> <span>Canvas</span>.SetLeft(rect, x);</li>
 <li> <span>Canvas</span>.SetTop(rect, y);</li>
 <li> }</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>// Список определений поведения, существующий на странице</span></li>
 <li> <span>readonly</span> <span>IList</span>&lt;<span>IBehavior</span>&lt;<span>FrameworkElement</span>&gt;&gt; _behaviors = <span>new</span> <span>List</span>&lt;<span>IBehavior</span>&lt;<span>FrameworkElement</span>&gt;&gt;();</li>
 <li>&#160;</li>
 <li> <span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li> <span>///</span><span> Функция, придаёт поведение перетаскивания всем элементам, лежащим на канвасе</span></li>
 <li> <span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li> <span>void</span> InitBehaviors()</li>
 <li> {</li>
 <li> <span>foreach</span> (<span>UIElement</span> uiElement <span>in</span> canvas.Children)</li>
 <li> {</li>
 <li> <span>if</span> (uiElement <span>is</span> <span>FrameworkElement</span>)</li>
 <li> {</li>
 <li> <span>var</span> element = uiElement <span>as</span> <span>FrameworkElement</span>;</li>
 <li> <span>var</span> dragBehavior = <span>new</span> <span>DragBehavior</span>&lt;<span>FrameworkElement</span>&gt;();</li>
 <li> dragBehavior.SetTarget(element);</li>
 <li> _behaviors.Add(dragBehavior);</li>
 <li> }</li>
 <li> }</li>
 <li> }</li>
 <li>}</li>
 </ol></div></div>После этих работ, получим результат, представленный на картинке ниже. <br/>
<div style="text-align: center"><!--noindex--><a href="https://lh5.googleusercontent.com/-bO1pE6V0i44/TvSw_-lDQgI/AAAAAAAAC44/0YChqck9GD0/s0-d/1.jpg" rel="nofollow" style="margin-left: 1em; margin-right: 1em"><img src="https://lh5.googleusercontent.com/-bO1pE6V0i44/TvSw_-lDQgI/AAAAAAAAC44/0YChqck9GD0/s0-d/1.jpg" width="611px" height="635px" border="0"/></a><!--/noindex--></div>Теперь весь код, который позволяет перетаскивать фигуры, находится в одном месте и его можно многократно использовать на различных контролах. Но это ещё не всё. Используюя возможности интерфейса IBehavior, можно определять не только перетаскивание, но вообще любое поведение. Для примера, создадим ещё один класс-поведение. Он будет при наведении на контрол увеличивать ему z-индекс, а также плавно увеличивать в размерах. А при потере курсора размер контрола должен плавно прийти в норму. Вот код класса:<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li><span>///</span><span> Класс при наведении на объект его увеличивает, а при потере курсора - уменьшает</span></li>
 <li><span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li><span>///</span><span> </span><span>&lt;typeparam name=&quot;T&quot;&gt;&lt;/typeparam&gt;</span></li>
 <li><span>public</span> <span>class</span> <span>HoverBehavior</span>&lt;T&gt; : <span>IBehavior</span>&lt;T&gt; <span>where</span> T:<span>FrameworkElement</span></li>
 <li>{</li>
 <li> <span>private</span> T _target;</li>
 <li> <span>private</span> <span>ScaleTransform</span> _scaleTransform;</li>
 <li> <span>private</span> <span>int</span> _oldZIndex;</li>
 <li>&#160;</li>
 <li> <span>public</span> <span>void</span> SetTarget(T target)</li>
 <li> {</li>
 <li> <span>if</span> (_target != <span>null</span>)</li>
 <li> {</li>
 <li> _target.MouseEnter -= TargetMouseEnter;</li>
 <li> _target.MouseLeave -= TargetMouseLeave;</li>
 <li> }</li>
 <li>&#160;</li>
 <li> _target = target;</li>
 <li>&#160;</li>
 <li> <span>if</span> (target != <span>null</span>)</li>
 <li> {</li>
 <li> _target.MouseEnter += TargetMouseEnter;</li>
 <li> _target.MouseLeave += TargetMouseLeave;</li>
 <li> }</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>void</span> TargetMouseLeave(<span>object</span> sender, System.Windows.Input.<span>MouseEventArgs</span> e)</li>
 <li> {</li>
 <li> <span>// Восстановление z-индекса и состояния объекта</span></li>
 <li> <span>Canvas</span>.SetZIndex(_target, _oldZIndex);</li>
 <li> _scaleTransform = GetScaleTransform(1.1);</li>
 <li> _target.RenderTransform = _scaleTransform;</li>
 <li> SetAnimation(1.1, 1, _scaleTransform);</li>
 <li> }</li>
 <li>&#160;</li>
 <li> </li>
 <li> <span>void</span> TargetMouseEnter(<span>object</span> sender, System.Windows.Input.<span>MouseEventArgs</span> e)</li>
 <li> {</li>
 <li> _oldZIndex = <span>Canvas</span>.GetZIndex(_target);</li>
 <li> <span>// Вывод объекта на передний план</span></li>
 <li> <span>Canvas</span>.SetZIndex(_target, 10000);</li>
 <li> _scaleTransform = GetScaleTransform(1);</li>
 <li> _target.RenderTransform = _scaleTransform;</li>
 <li> SetAnimation(1, 1.1, _scaleTransform);</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>#region</span> Получение и установвка преобразований и анимаций </li>
 <li>&#160;</li>
 <li> <span>private</span> <span>void</span> SetAnimation(<span>double</span> from, <span>double</span> to, <span>Transform</span> transform)</li>
 <li> {</li>
 <li> <span>var</span> doubleAnimationX = GetDoubleAnimation(from, to, transform, <span>&quot;ScaleX&quot;</span>);</li>
 <li> <span>var</span> doubleAnimationY = GetDoubleAnimation(from, to, transform, <span>&quot;ScaleY&quot;</span>);</li>
 <li>&#160;</li>
 <li> <span>var</span> storyBoard = <span>new</span> <span>Storyboard</span>();</li>
 <li> storyBoard.Children.Add(doubleAnimationX);</li>
 <li> storyBoard.Children.Add(doubleAnimationY);</li>
 <li>&#160;</li>
 <li> storyBoard.Begin();</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>private</span> <span>ScaleTransform</span> GetScaleTransform(<span>double</span> scale)</li>
 <li> {</li>
 <li> <span>return</span> <span>new</span> <span>ScaleTransform</span></li>
 <li> {</li>
 <li> CenterX = _target.Height * 0.5,</li>
 <li> CenterY = _target.Width * 0.5,</li>
 <li> ScaleX = scale,</li>
 <li> ScaleY = scale</li>
 <li> };</li>
 <li> }</li>
 <li>&#160;</li>
 <li> <span>private</span> <span>Timeline</span> GetDoubleAnimation(<span>double</span> from, <span>double</span> to, <span>Transform</span> transform, <span>string</span> property)</li>
 <li> {</li>
 <li> <span>var</span> doubleAnimation = <span>new</span> <span>DoubleAnimation</span></li>
 <li> {</li>
 <li> Duration = <span>new</span> <span>Duration</span>(<span>new</span> <span>TimeSpan</span>(0, 0, 1)),</li>
 <li> From = from,</li>
 <li> To = to</li>
 <li> };</li>
 <li>&#160;</li>
 <li> <span>Storyboard</span>.SetTarget(doubleAnimation, transform);</li>
 <li> <span>Storyboard</span>.SetTargetProperty(doubleAnimation, <span>new</span> <span>PropertyPath</span>(property));</li>
 <li>&#160;</li>
 <li> <span>return</span> doubleAnimation;</li>
 <li> } </li>
 <li> <span>#endregion</span></li>
 <li>}</li>
 </ol></div></div>Остаётся только изменить одну функцию на странице, добавить в неё создание и привязку только что созданного поведения<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li><span>///</span><span> Функция, придаёт поведение перетаскивания всем элементам, лежащим на канвасе</span></li>
 <li><span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li><span>void</span> InitBehaviors()</li>
 <li>{</li>
 <li> <span>foreach</span> (<span>UIElement</span> uiElement <span>in</span> canvas.Children)</li>
 <li> {</li>
 <li> <span>if</span> (uiElement <span>is</span> <span>FrameworkElement</span>)</li>
 <li> {</li>
 <li> <span>var</span> element = uiElement <span>as</span> <span>FrameworkElement</span>;</li>
 <li> <span>var</span> dragBehavior = <span>new</span> <span>DragBehavior</span>&lt;<span>FrameworkElement</span>&gt;();</li>
 <li> dragBehavior.SetTarget(element);</li>
 <li> _behaviors.Add(dragBehavior);</li>
 <li> </li>
 <li> <span>var</span> hoverBehavior = <span>new</span> <span>HoverBehavior</span>&lt;<span>FrameworkElement</span>&gt;();</li>
 <li> hoverBehavior.SetTarget(element);</li>
 <li> _behaviors.Add(hoverBehavior);</li>
 <li> }</li>
 <li> }</li>
 <li>}</li>
 </ol></div></div>Вы можете скачать <!--noindex--><a href="http://dl.dropbox.com/u/38076493/PostDemos/Silverlight/DragBehavior/SilverlightApplication1.zip" rel="nofollow">исходники</a><!--/noindex-->. или поглядеть живое демо прямо сейчас:<br/>
<br/>
В результате работы мы, написав сравнительно немного кода, смогли применить его несколько раз на различный контролах. Удобно, не правда ли? Кажется, что интерфейс поведения должен быть частью Silverlight - и непонятно, почему они его не включили. Однако, порыскав в интернете, я всё таки нашел, что искал. Оказывается для реализации поведения можно использовать <!--noindex--><a href="http://msdn.microsoft.com/en-us/library/ff726531(v=expression.40).aspx" rel="nofollow">Behavior Generic Class</a><!--/noindex-->, но вот найти его можно только в составе Expression Studio. Он находится в сборке System.Windows.Interactivity.dll, которая расположена по адресу (по крайней мере у меня) C:\Program Files (x86)\Microsoft SDKs\Expression\Blend\Silverlight\v4.0\Libraries. Поковыряв программой ILSpy, обнаружим в сборке пару интересных классов. Чтобы не загромождать пост лишним кодом, я покажу только публичные методы классов.<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>using</span> System;</li>
 <li><span>using</span> System.Globalization;</li>
 <li><span>namespace</span> System.Windows.Interactivity</li>
 <li>{</li>
 <li> <span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li> <span>///</span><span> Encapsulates state information and zero or more ICommands into an attachable object.</span></li>
 <li> <span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li> <span>///</span><span> </span><span>&lt;remarks&gt;</span><span>This is an infrastructure class. Behavior authors should derive from Behavior&amp;lt;T&amp;gt; instead of from this class.</span><span>&lt;/remarks&gt;</span></li>
 <li> <span>public</span> <span>abstract</span> <span>class</span> <span>Behavior</span> : <span>DependencyObject</span>, <span>IAttachedObject</span></li>
 <li> {</li>
 <li> <span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li> <span>///</span><span> Attaches to the specified object.</span></li>
 <li> <span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li> <span>///</span><span> </span><span>&lt;param name=&quot;dependencyObject&quot;&gt;</span><span>The object to attach to.</span><span>&lt;/param&gt;</span></li>
 <li> <span>///</span><span> </span><span>&lt;exception cref=&quot;T:System.InvalidOperationException&quot;&gt;</span><span>The Behavior is already hosted on a different element.</span><span>&lt;/exception&gt;</span></li>
 <li> <span>///</span><span> </span><span>&lt;exception cref=&quot;T:System.InvalidOperationException&quot;&gt;</span><span>dependencyObject does not satisfy the Behavior type constraint.</span><span>&lt;/exception&gt;</span></li>
 <li> <span>public</span> <span>void</span> Attach(<span>DependencyObject</span> dependencyObject);</li>
 <li>&#160;</li>
 <li> <span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li> <span>///</span><span> Detaches this instance from its associated object.</span></li>
 <li> <span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li> <span>public</span> <span>void</span> Detach();</li>
 <li> }</li>
 <li>}</li>
 </ol></div></div><br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>using</span> System;</li>
 <li><span>namespace</span> System.Windows.Interactivity</li>
 <li>{</li>
 <li> <span>///</span><span> </span><span>&lt;summary&gt;</span></li>
 <li> <span>///</span><span> Encapsulates state information and zero or more ICommands into an attachable object.</span></li>
 <li> <span>///</span><span> </span><span>&lt;/summary&gt;</span></li>
 <li> <span>///</span><span> </span><span>&lt;typeparam name=&quot;T&quot;&gt;</span><span>The type the </span><span>&lt;see cref=&quot;T:System.Windows.Interactivity.Behavior`1&quot; /&gt;</span><span> can be attached to.</span><span>&lt;/typeparam&gt;</span></li>
 <li> <span>///</span><span> </span><span>&lt;remarks&gt;</span></li>
 <li> <span>///</span><span> Behavior is the base class for providing attachable state and commands to an object.</span></li>
 <li> <span>///</span><span> The types the Behavior can be attached to can be controlled by the generic parameter.</span></li>
 <li> <span>///</span><span> Override OnAttached() and OnDetaching() methods to hook and unhook any necessary handlers</span></li>
 <li> <span>///</span><span> from the AssociatedObject.</span></li>
 <li> <span>///</span><span> </span><span>&lt;/remarks&gt;</span></li>
 <li> <span>public</span> <span>abstract</span> <span>class</span> <span>Behavior</span>&lt;T&gt; : Behavior <span>where</span> T : <span>DependencyObject</span></li>
 <li> {</li>
 <li> }</li>
 <li>}</li>
 </ol></div></div><br/>
После изложенного мной материала выше, назначение показанных методов очевидно.<br/>
Это всё. Всем спасибо.<br/>
<br/>
Полезные ссылки<br/>
<!--noindex--><a href="http://blendworld.net/post/2009/04/04/Behaviors-in-Silverlight-3.aspx" rel="nofollow">Поведение (Behaviors) контролов в Silverlight 3</a><!--/noindex--><br/>
<!--noindex--><a href="http://wildermuth.com/2009/05/16/Writing_Behaviors_for_Silverlight_3_-_Part_1" rel="nofollow">Writing Behaviors for Silverlight 3</a><!--/noindex--><br/>
<!--noindex--><a href="http://www.85turns.com/2009/10/14/top-5-silverlight-behaviors/" rel="nofollow">Top 5 Silverlight Behaviors</a><!--/noindex--><br/>
</div><div><img src="https://blogger.googleusercontent.com/tracker/8897990838383834685-8574037952856322416?l=tym32167.blogspot.com" width="1px" height="1px" border="0"/></div>]]></description>
      <category><![CDATA[Silverlight]]></category>
      <category><![CDATA[Behavior]]></category>
      <guid>http://tym32167.blogspot.com/2011/12/silverlight.html</guid>
      <pubDate>Fri, 23 Dec 2011 19:00:00 UT</pubDate>
      <dc:creator><![CDATA[tym32167]]></dc:creator>
    </item>
    <item>
      <title><![CDATA[Получение количества строк в каждой таблице базы данных]]></title>
      <link>http://microgeek.ru/blogs/tym32167/1712/</link>
      <description><![CDATA[<div style="text-align: left">Для работы мне нужно было подсчитать количество строк во всех таблицах схемы. Писать селект для каждой таблицы было лень, потому пришла мысль написать один скрипт, который можно было бы использовать на разных базах данных без модификации. Что из этого получилось.<br/>
<a name="more" rel="nofollow"></a><br/>
Должен пояснить, что скрипт я пишу для Sql Server 2008 R2. Для запроса я решил использовать системное представление информационной схемы <!--noindex--><a href="http://msdn.microsoft.com/ru-ru/library/ms186224.aspx" rel="nofollow">TABLES</a><!--/noindex-->, хотя для нахождения схемы таблицы его и не рекомендуют, я пока не встретил ни одного случая, где схема, указанная в представлении, не соответствовала реальной схеме базы данных. Далее скрипт и скриншот.<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>-- Код, получает количество строк во всех таблицах</span></li>
 <li>&#160;</li>
 <li><span>-- тут будет храниться список запросов к каждой таблице в базе</span></li>
 <li><span>DECLARE</span> <span>@sqls</span> <span>TABLE </span><span>(</span><span>rownumber</span> <span>int</span><span>,</span> <span>sqls</span> <span>varchar</span><span>(</span><span>max</span><span>))</span> <span>;</span></li>
 <li>&#160;</li>
 <li><span>-- это для прохода по таблице</span></li>
 <li><span>DECLARE</span> <span>@i</span> <span>bigint</span><span>;</span></li>
 <li><span>DECLARE</span> <span>@numrows</span> <span>bigint</span><span>;</span></li>
 <li>&#160;</li>
 <li><span>-- временная переменная</span></li>
 <li><span>DECLARE</span> <span>@temp</span> <span>varchar</span><span>(</span><span>max</span><span>);</span></li>
 <li>&#160;</li>
 <li><span>-- тут будет результирующий запрос</span></li>
 <li><span>DECLARE</span> <span>@SQL</span> <span>varchar</span><span>(</span><span>max</span><span>)</span> <span>=</span> <span>''</span><span>;</span></li>
 <li>&#160;</li>
 <li><span>-- получаем запросы к каждой таблице в базе</span></li>
 <li><span>INSERT</span> <span>INTO</span> <span>@sqls</span><span> </span><span>(</span><span>rownumber</span><span>,</span> <span>sqls</span><span>)</span></li>
 <li><span>SELECT</span> </li>
 <li><span>-- номер строки в результате - нам понадобится при перечислении</span></li>
 <li><span>ROW_NUMBER</span><span>()</span> </li>
 <li><span>OVER </span><span>(</span></li>
 <li><span>ORDER</span> <span>BY</span></li>
 <li><span>t</span><span>.</span><span>TABLE_CATALOG</span><span>,</span></li>
 <li><span>t</span><span>.</span><span>TABLE_SCHEMA</span><span>,</span></li>
 <li><span>t</span><span>.</span><span>TABLE_NAME</span></li>
 <li><span>),</span></li>
 <li><span>-- Сам запрос в виде SELECT ('БазаДаных.Схема.Таблица') as TableName, (SELECT COUNT(*) FROM БазаДаных.Схема.Таблица) as cnt</span></li>
 <li><span>'SELECT ('''</span> <span>+</span></li>
 <li><span>t</span><span>.</span><span>TABLE_CATALOG</span> <span>+</span> <span>'.'</span> <span>+</span></li>
 <li><span>t</span><span>.</span><span>TABLE_SCHEMA</span> <span>+</span> <span>'.'</span> <span>+</span></li>
 <li><span>t</span><span>.</span><span>TABLE_NAME</span> </li>
 <li><span>+</span> <span>''') as TableName, '</span> <span>+</span></li>
 <li><span>'(SELECT COUNT(*) FROM '</span> <span>+</span> </li>
 <li><span>t</span><span>.</span><span>TABLE_CATALOG</span> <span>+</span> <span>'.'</span> <span>+</span></li>
 <li><span>t</span><span>.</span><span>TABLE_SCHEMA</span> <span>+</span> <span>'.'</span> <span>+</span></li>
 <li><span>t</span><span>.</span><span>TABLE_NAME</span> <span>+</span></li>
 <li><span>') as cnt'</span></li>
 <li><span>-- все нужные нам данные находятся в таблице INFORMATION_SCHEMA.TABLES</span></li>
 <li><span>FROM</span> <span>INFORMATION_SCHEMA</span><span>.</span><span>TABLES</span> <span>t</span></li>
 <li><span>WHERE</span> </li>
 <li><span>t</span><span>.</span><span>TABLE_TYPE</span> <span>=</span> <span>'BASE TABLE'</span> <span>-- Указывает, что мы ищем по таблицам</span></li>
 <li><span>ORDER</span> <span>BY</span></li>
 <li><span>t</span><span>.</span><span>TABLE_CATALOG</span><span>,</span></li>
 <li><span>t</span><span>.</span><span>TABLE_SCHEMA</span><span>,</span></li>
 <li><span>t</span><span>.</span><span>TABLE_NAME</span></li>
 <li>&#160;</li>
 <li>&#160;</li>
 <li><span>-- Цикл. Тут нужно обойти все полученные записи и просто сцепить в один запрос, через UNION ALL</span></li>
 <li><span>-- i - просто счётчик от 1 до numrows</span></li>
 <li><span>SET</span> <span>@i</span> <span>=</span> 1</li>
 <li><span>SET</span> <span>@numrows</span> <span>=</span><span> </span><span>(</span><span>SELECT</span> <span>COUNT</span><span>(*)</span> <span>FROM</span> <span>@sqls</span><span>)</span></li>
 <li><span>IF</span> <span>@numrows</span> <span>&gt;</span> 0</li>
 <li> <span>WHILE </span><span>(</span><span>@i</span> <span>&lt;=</span><span> </span><span>(</span><span>SELECT</span> <span>MAX</span><span>(</span><span>rownumber</span><span>)</span> <span>FROM</span> <span>@sqls</span><span>))</span></li>
 <li> <span>BEGIN</span></li>
 <li> <span>-- Получаем нужную строку</span></li>
 <li> <span>SET</span> <span>@temp</span> <span>=</span><span> </span><span>(</span><span>SELECT</span> <span>sqls</span> <span>FROM</span> <span>@sqls</span> <span>WHERE</span> <span>rownumber</span> <span>=</span> <span>@i</span><span>)</span> </li>
 <li> </li>
 <li> <span>-- Склеиваем</span></li>
 <li> <span>IF </span><span>(</span><span>@i</span> <span>=</span> 1<span>)</span></li>
 <li> <span>BEGIN</span></li>
 <li> <span>SET</span> <span>@SQL</span> <span>=</span> <span>@temp</span><span>;</span></li>
 <li> <span>END</span> </li>
 <li> <span>ELSE</span></li>
 <li> <span>BEGIN</span></li>
 <li> <span>SET</span> <span>@SQL</span> <span>=</span> <span>@SQL</span> <span>+</span> <span>' UNION ALL '</span><span>+</span> <span>@temp</span><span>;</span></li>
 <li> <span>END</span> </li>
 <li> </li>
 <li> <span>-- Увеличиваем счётчик </span></li>
 <li> <span>SET</span> <span>@i</span> <span>=</span> <span>@i</span> <span>+</span> 1</li>
 <li> <span>END</span></li>
 <li>&#160;</li>
 <li><span>-- Выполняем полученный запрос</span></li>
 <li><span>EXEC</span><span>(</span><span>@SQL</span><span>)</span></li>
 </ol></div></div>В результате выполнения скрипта я получил то, чего ожидал.<br/>
<div style="text-align: center"><!--noindex--><a href="https://lh4.googleusercontent.com/-iX-7Ngh5N10/TvOBKTCmokI/AAAAAAAAC4s/izt4QHTFJ6I/s0-d/1.PNG" rel="nofollow" style="margin-left: 1em; margin-right: 1em"><img src="https://lh4.googleusercontent.com/-iX-7Ngh5N10/TvOBKTCmokI/AAAAAAAAC4s/izt4QHTFJ6I/s0-d/1.PNG" width="836px" border="0"/></a><!--/noindex--></div>Конечно, можно было сделать и через курсоры. Но этот вариант мне кажется проще.<br/>
<br/>
<br/>
UPD.<br/>
<br/>
Переписал скрипт с учетом того, что представление TABLE не рекомендуют для получения названия схемы. Для этого использовал системную таблицу <!--noindex--><a href="http://msdn.microsoft.com/ru-ru/library/ms190324.aspx" rel="nofollow">sys.objects (Transact-SQL)</a><!--/noindex--> и функцию <!--noindex--><a href="http://msdn.microsoft.com/ru-ru/library/ms175068.aspx" rel="nofollow">SCHEMA_NAME (Transact-SQL)</a><!--/noindex--><br/>
<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>-- Код, получает количество строк во всех таблицах</span></li>
 <li> </li>
 <li><span>-- тут будет храниться список запросов к каждой таблице в базе</span></li>
 <li><span>DECLARE</span> <span>@sqls</span> <span>TABLE </span><span>(</span><span>rownumber</span> <span>int</span><span>,</span> <span>sqls</span> <span>varchar</span><span>(</span><span>max</span><span>))</span> <span>;</span></li>
 <li> </li>
 <li><span>-- это для прохода по таблице</span></li>
 <li><span>DECLARE</span> <span>@i</span> <span>bigint</span><span>;</span></li>
 <li><span>DECLARE</span> <span>@numrows</span> <span>bigint</span><span>;</span></li>
 <li> </li>
 <li><span>-- временная переменная</span></li>
 <li><span>DECLARE</span> <span>@temp</span> <span>varchar</span><span>(</span><span>max</span><span>);</span></li>
 <li> </li>
 <li><span>-- тут будет результирующий запрос</span></li>
 <li><span>DECLARE</span> <span>@SQL</span> <span>varchar</span><span>(</span><span>max</span><span>)</span> <span>=</span> <span>''</span><span>;</span></li>
 <li> </li>
 <li><span>-- получаем запросы к каждой таблице в базе</span></li>
 <li><span>INSERT</span> <span>INTO</span> <span>@sqls</span><span> </span><span>(</span><span>rownumber</span><span>,</span> <span>sqls</span><span>)</span></li>
 <li><span>SELECT</span></li>
 <li><span>-- номер строки в результате - нам понадобится при перечислении</span></li>
 <li><span>ROW_NUMBER</span><span>()</span></li>
 <li><span>OVER </span><span>(</span></li>
 <li><span>ORDER</span> <span>BY</span></li>
 <li><span>t</span><span>.</span><span>TABLE_CATALOG</span><span>,</span></li>
 <li><span>SCHEMA_NAME</span><span>(</span><span>ob</span><span>.</span><span>schema_id</span><span>),</span></li>
 <li><span>t</span><span>.</span><span>TABLE_NAME</span></li>
 <li><span>),</span></li>
 <li><span>-- Сам запрос в виде SELECT ('БазаДаных.Схема.Таблица') as TableName, (SELECT COUNT(*) FROM БазаДаных.Схема.Таблица) as cnt</span></li>
 <li><span>'SELECT ('''</span> <span>+</span></li>
 <li><span>t</span><span>.</span><span>TABLE_CATALOG</span> <span>+</span> <span>'.'</span> <span>+</span></li>
 <li><span>SCHEMA_NAME</span><span>(</span><span>ob</span><span>.</span><span>schema_id</span><span>)</span> <span>+</span> <span>'.'</span> <span>+</span></li>
 <li><span>t</span><span>.</span><span>TABLE_NAME</span></li>
 <li><span>+</span> <span>''') as TableName, '</span> <span>+</span></li>
 <li><span>'(SELECT COUNT(*) FROM '</span> <span>+</span></li>
 <li><span>t</span><span>.</span><span>TABLE_CATALOG</span> <span>+</span> <span>'.'</span> <span>+</span></li>
 <li><span>SCHEMA_NAME</span><span>(</span><span>ob</span><span>.</span><span>schema_id</span><span>)</span> <span>+</span> <span>'.'</span> <span>+</span></li>
 <li><span>t</span><span>.</span><span>TABLE_NAME</span> <span>+</span></li>
 <li><span>') as cnt'</span></li>
 <li><span>-- все нужные нам данные находятся в таблице INFORMATION_SCHEMA.TABLES</span></li>
 <li><span>FROM</span> </li>
 <li> <span>INFORMATION_SCHEMA</span><span>.</span><span>TABLES</span> <span>t</span> <span>INNER</span> <span>JOIN</span> </li>
 <li> <span>sys</span><span>.</span><span>objects</span> <span>ob</span> <span>ON</span> <span>ob</span><span>.</span><span>[name]</span> <span>=</span> <span>t</span><span>.</span><span>TABLE_NAME</span></li>
 <li><span>WHERE</span></li>
 <li><span>t</span><span>.</span><span>TABLE_TYPE</span> <span>=</span> <span>'BASE TABLE'</span> <span>-- Указывает, что мы ищем по таблицам</span></li>
 <li><span>ORDER</span> <span>BY</span></li>
 <li><span>t</span><span>.</span><span>TABLE_CATALOG</span><span>,</span></li>
 <li><span>SCHEMA_NAME</span><span>(</span><span>ob</span><span>.</span><span>schema_id</span><span>),</span></li>
 <li><span>t</span><span>.</span><span>TABLE_NAME</span></li>
 <li> </li>
 <li> </li>
 <li><span>-- Цикл. Тут нужно обойти все полученные записи и просто сцепить в один запрос, через UNION ALL</span></li>
 <li><span>-- i - просто счётчик от 1 до numrows</span></li>
 <li><span>SET</span> <span>@i</span> <span>=</span> 1</li>
 <li><span>SET</span> <span>@numrows</span> <span>=</span><span> </span><span>(</span><span>SELECT</span> <span>COUNT</span><span>(*)</span> <span>FROM</span> <span>@sqls</span><span>)</span></li>
 <li><span>IF</span> <span>@numrows</span> <span>&gt;</span> 0</li>
 <li> <span>WHILE </span><span>(</span><span>@i</span> <span>&lt;=</span><span> </span><span>(</span><span>SELECT</span> <span>MAX</span><span>(</span><span>rownumber</span><span>)</span> <span>FROM</span> <span>@sqls</span><span>))</span></li>
 <li> <span>BEGIN</span></li>
 <li> <span>-- Получаем нужную строку</span></li>
 <li> <span>SET</span> <span>@temp</span> <span>=</span><span> </span><span>(</span><span>SELECT</span> <span>sqls</span> <span>FROM</span> <span>@sqls</span> <span>WHERE</span> <span>rownumber</span> <span>=</span> <span>@i</span><span>)</span> </li>
 <li> </li>
 <li> <span>-- Склеиваем</span></li>
 <li> <span>IF </span><span>(</span><span>@i</span> <span>=</span> 1<span>)</span></li>
 <li> <span>BEGIN</span></li>
 <li> <span>SET</span> <span>@SQL</span> <span>=</span> <span>@temp</span><span>;</span></li>
 <li> <span>END</span> </li>
 <li> <span>ELSE</span></li>
 <li> <span>BEGIN</span></li>
 <li> <span>SET</span> <span>@SQL</span> <span>=</span> <span>@SQL</span> <span>+</span> <span>' UNION ALL '</span><span>+</span> <span>@temp</span><span>;</span></li>
 <li> <span>END</span> </li>
 <li> </li>
 <li> <span>-- Увеличиваем счётчик </span></li>
 <li> <span>SET</span> <span>@i</span> <span>=</span> <span>@i</span> <span>+</span> 1</li>
 <li> <span>END</span></li>
 <li> </li>
 <li><span>-- Выполняем полученный запрос</span></li>
 <li><span>EXEC</span><span>(</span><span>@SQL</span><span>)</span></li>
 </ol></div></div><br/>
Как верно заметили в комментариях, можно также использовать недокументированные возможности и получить аналогичный результат<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>CREATE</span> <span>TABLE</span> <span>#counts</span></li>
 <li><span>(</span></li>
 <li> <span>table_name</span> <span>varchar</span><span>(</span>255<span>),</span></li>
 <li> <span>row_count</span> <span>int</span></li>
 <li><span>)</span></li>
 <li>&#160;</li>
 <li><span>EXEC</span> <span>sp_MSForEachTable</span><span> </span><span>@command1</span><span>=</span><span>'INSERT #counts (table_name, row_count) SELECT ''?'', COUNT(*) FROM ?'</span></li>
 <li><span>SELECT</span> <span>table_name</span><span>,</span> <span>row_count</span> <span>FROM</span> <span>#counts</span> <span>ORDER</span> <span>BY</span> <span>table_name</span><span>,</span> <span>row_count</span> <span>DESC</span></li>
 <li>&#160;</li>
 <li><span>DROP</span> <span>TABLE</span> <span>#counts</span><span>;</span></li>
 </ol></div></div><br/>
Код, конечно, стал меньше. Но недокументированные возможности ведут за собой недокументррованные ошибки. <br/>
Также есть ещё вариант получения количества строк в таблицах<br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>SELECT</span></li>
 <li> <span>o</span><span>.</span><span>Name</span><span>,</span></li>
 <li> <span>i</span><span>.</span><span>rows</span> </li>
 <li><span>FROM</span> <span>sysobjects</span> <span>o</span></li>
 <li><span>INNER</span> <span>JOIN</span> <span>sysindexes</span> <span>i</span></li>
 <li><span>ON </span><span>(</span><span>o</span><span>.</span><span>id</span> <span>=</span> <span>i</span><span>.</span><span>id</span><span>)</span></li>
 <li><span>WHERE</span> <span>o</span><span>.</span><span>xtype</span> <span>=</span> <span>'u'</span></li>
 <li><span>AND</span> <span>i</span><span>.</span><span>indid</span> <span>&lt;</span> 2</li>
 <li><span>ORDER</span> <span>BY</span> <span>o</span><span>.</span><span>name</span></li>
 </ol></div></div><br/>
Но в этом случае есть вероятность, что данные будут неактуальные.<br/>
<br/>
UPD2. Если Вам достаточно получить примерное количество строк в таблице, то можно воспользоваться представлением <!--noindex--><a href="http://msdn.microsoft.com/ru-ru/library/ms175012.aspx" rel="nofollow">sys.partitions (Transact-SQL)</a><!--/noindex--><br/>
<br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>SELECT</span></li>
 <li> <span>schema_name</span><span>(</span><span>o</span><span>.</span><span>schema_id</span><span>)</span> <span>+</span> <span>'.'</span> <span>+</span> <span>o</span><span>.</span><span>Name</span><span>,</span></li>
 <li> <span>p</span><span>.</span><span>rows</span></li>
 <li><span>FROM</span> <span>sys</span><span>.</span><span>objects</span> <span>o</span></li>
 <li> <span>INNER</span> <span>JOIN</span> <span>sys</span><span>.</span><span>partitions</span> <span>p</span></li>
 <li> <span>ON </span><span>(</span><span>o</span><span>.</span><span>object_id</span> <span>=</span> <span>p</span><span>.</span><span>object_id</span><span>)</span></li>
 <li><span>WHERE</span> </li>
 <li> <span>o</span><span>.</span><span>type</span> <span>=</span> <span>'u'</span> </li>
 <li> <span>AND</span> <span>p</span><span>.</span><span>index_id</span> <span>&lt;</span> 2</li>
 <li><span>ORDER</span> <span>BY</span> </li>
 <li> <span>schema_name</span><span>(</span><span>o</span><span>.</span><span>schema_id</span><span>)</span> <span>+</span> <span>'.'</span> <span>+</span> <span>o</span><span>.</span><span>Name</span></li>
 </ol></div></div><br/>
Код получился намного короче, но в результате может быть погрешность.<br/>
<br/>
UPD3.<br/>
<br/>
В результате изучения документации, я всё таки нашел способ точного подсчёта количества строк в таблицах. Для этого следовало использовать представление <!--noindex--><a href="http://msdn.microsoft.com/ru-ru/library/ms187737(v=SQL.105).aspx" rel="nofollow">sys.dm_db_partition_stats (Transact-SQL)</a><!--/noindex--><br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span>SELECT</span></li>
 <li> <span>schema_name</span><span>(</span><span>o</span><span>.</span><span>schema_id</span><span>)</span> <span>+</span> <span>'.'</span> <span>+</span> <span>o</span><span>.</span><span>Name</span><span>,</span></li>
 <li> <span>p</span><span>.</span><span>row_count</span></li>
 <li><span>FROM</span> <span>sys</span><span>.</span><span>objects</span> <span>o</span></li>
 <li> <span>INNER</span> <span>JOIN</span> <span>sys</span><span>.</span><span>dm_db_partition_stats</span> <span>p</span></li>
 <li> <span>ON </span><span>(</span><span>o</span><span>.</span><span>object_id</span> <span>=</span> <span>p</span><span>.</span><span>object_id</span><span>)</span></li>
 <li><span>WHERE</span> </li>
 <li> <span>o</span><span>.</span><span>type</span> <span>=</span> <span>'u'</span> </li>
 <li> <span>AND</span> <span>p</span><span>.</span><span>index_id</span> <span>&lt;</span> 2</li>
 <li><span>ORDER</span> <span>BY</span> </li>
 <li> <span>schema_name</span><span>(</span><span>o</span><span>.</span><span>schema_id</span><span>)</span> <span>+</span> <span>'.'</span> <span>+</span> <span>o</span><span>.</span><span>Name</span></li>
 </ol></div></div><br/>
Этот способ нахождения количества строк в таблицах базы данных мне кажется самым лучшим из представленных.<br/>
<br/>
<br/>
</div><div><img src="https://blogger.googleusercontent.com/tracker/8897990838383834685-8649835697484086809?l=tym32167.blogspot.com" width="1px" height="1px" border="0"/></div>]]></description>
      <category><![CDATA[sql]]></category>
      <category><![CDATA[scripts]]></category>
      <category><![CDATA[sql server]]></category>
      <guid>http://tym32167.blogspot.com/2011/12/blog-post.html</guid>
      <pubDate>Thu, 22 Dec 2011 19:24:00 UT</pubDate>
      <dc:creator><![CDATA[tym32167]]></dc:creator>
    </item>
    <item>
      <title><![CDATA[CloudShare – облачный сервис для создания серверов с SharePoint и не только]]></title>
      <link>http://microgeek.ru/blogs/dplotnikov/1699/</link>
      <description><![CDATA[<p><img src="http://dplotnikov.files.wordpress.com/2011/12/clip_image001.png" width="348px" height="209px" border="0" align="left"/></p> <p>При установке SharePoint возникают различные проблемы, и сам процесс может занять много времени. Некоторые <!--noindex--><a href="http://dplotnikov.wordpress.com/2011/09/28/новые-тестовые-виртуальные-машины-sp1/" rel="nofollow">загружают уже готовые образы</a><!--/noindex--> в виде VHD, и работают с ними.</p> <p>Но что делать, если негде установить SharePoint или подключить VHD? Можно воспользоваться сервисом CloudShare, позволяющим в несколько кликов начать пользоваться SharePoint.</p> <h4>Спецификации</h4> <ul><li>Что входит в ваше облако (тарифный план CloudShare ProPlus) </li>
 <li>Количество машин – от 1 до 6. Каждая машина и софт на ней лицензированы. Это может быть <ul><li>SharePoint 2010 Enterprise </li>
 <li>SharePoint 2010 Information Worker </li>
 <li>SharePoint Foundation 2010 </li>
 <li>SharePoint Foundation 2010 with Dev Tools </li>
 <li>SharePoint 2007 Enterprise </li>
 <li>CentOS 5 with MySQL </li>
 <li>Windows 2003 R2 with Oracle 11g </li>
 <li>Windows 2008 R2 Active Directory </li>
 <li>и т.д. Полный список доступных машин можно посмотреть <!--noindex--><a href="http://www.cloudshare.com/Products/CloudShare-ProPlus/available_machines.aspx" rel="nofollow">здесь</a><!--/noindex-->. </li>
 </ul> </li>
 <li>Возможность настроить сеть между виртуальными машинами </li>
 <li>На все машины в сумме выделяется 10 ГБ RAM, 300 ГБ HDD и 10 виртуальных CPU </li>
 <li>Поддержка 24/7 по email и на форуме </li>
 </ul> <h4>Кому это может быть полезно?</h4> <p>Сервис может быть полезен разработчикам, ИТ профессионалам, менеджерам отдела продаж, тренерам и всем, кому необходимо работать с несколькими окружениями, или не хочется тратить время на администрирование операционных систем. </p> <h4>Чем это может быть полезно?</h4> <p>Фактически нет нужды тратить время на администрирование операционных систем (рис. 1). Также удобно, что есть механизм снимков (Snapshot), позволяющий бысто создать копию вашего окружения. </p> <p><img src="http://dplotnikov.files.wordpress.com/2011/12/image.png" border="0"/> </p> <p>Рис. 1. Панель администрирования в CloudShare </p> <p>При необходимости можно предоставить доступ для внешних пользователей (полезно для различных демонстраций и совместной работы). </p> <p>Немаловажно, что при необходимости автоматически увеличивается RAM, но на ограниченное время. </p> <p>Создать новое окружение просто, для этого надо пройти трехшаговый процесс (рис. 2) </p> <p>1. Выбираем машины, которые будут в окружении </p> <p><img src="http://dplotnikov.files.wordpress.com/2011/12/image1.png" border="0"/> </p> <p>2. Указываем описание окружения </p> <p><img src="http://dplotnikov.files.wordpress.com/2011/12/image2.png" border="0"/> </p> <p>3. Запускаем! </p> <p><img src="http://dplotnikov.files.wordpress.com/2011/12/image3.png" border="0"/> </p> <p>Таким образом, сервис позволяет вам сконцентрироваться на работе, забыв про администрирование. </p> <h4>А как же недостатки?</h4> <p>Самый существенный недостаток – если вы не используете какое-то время ваше окружение, то его работа приостанавливается. Причина очень проста – данный тарифный план не подразумевает использование сервиса в качестве Enterprise решения. Для этого случая есть дополнительная опция ($599 в месяц) или тарифный план <!--noindex--><a href="http://www.cloudshare.com/Products/CloudShare-Enterprise/CloudShare-Enterprise.aspx" rel="nofollow">CloudShare Enterprise</a><!--/noindex--> </p> <h4>Сколько это стоит?</h4> <p>$49 в месяц </p> <p>$490 в год </p> <p>До 31 декабря действует скидка в $91 на годовую подписку, которая будет стоить $399. Для получения скидки используйте код <b>holiday</b> </p> ]]></description>
      <category><![CDATA[sharepoint]]></category>
      <category><![CDATA[cloud]]></category>
      <category><![CDATA[cloudshare]]></category>
      <guid isPermaLink="false">urn:bitrix:blog:post:1699</guid>
      <pubDate>Wed, 21 Dec 2011 10:06:11 UT</pubDate>
      <dc:creator><![CDATA[Dmitry Plotnikov]]></dc:creator>
    </item>
    <item>
      <title><![CDATA[Готовим вкусный блокнот из AvalonEdit и AvalonDock]]></title>
      <link>http://microgeek.ru/blogs/tym32167/1711/</link>
      <description><![CDATA[<div style="text-align: left">Всем привет. Сегодня хочу поделиться опытом работы с контролами <!--noindex--><a href="http://wiki.sharpdevelop.net/AvalonEdit.ashx" rel="nofollow">AvalonEdit</a><!--/noindex--> и <!--noindex--><a href="http://avalondock.codeplex.com/" rel="nofollow">AvalonDock</a><!--/noindex--><br/>
Итак, моя цель - сделать блокнот с подсветкой синтаксиса, intellisense и оконным интерфейсом, как у Visual Studio 2010.<br/>
<a name="more" rel="nofollow"></a><br/>
В качестве оправной точки я использую статьи по работе с данными контролами (<!--noindex--><a href="http://www.codeproject.com/KB/edit/AvalonEdit.aspx" rel="nofollow">Using AvalonEdit (WPF Text Editor)</a><!--/noindex-->, <!--noindex--><a href="http://www.codeproject.com/KB/WPF/WPFdockinglib.aspx" rel="nofollow">WPF Docking Library</a><!--/noindex-->). Ознакомившись с данным материалом, я начал с оконного интерфейса. Это оказалось очень просто:<br/>
Используем DockingManager на главной странице:<br/>
<div style="color: black; font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2em; padding: 0 0 0 5px"><li><span style="color: blue">&lt;</span><span>ad</span><span style="color: blue">:</span><span>DockingManager</span><span style="color: red"> x</span><span style="color: blue">:</span><span style="color: red">Name</span><span style="color: blue">=&quot;DockManager&quot;</span><span style="color: red"> IsAnimationEnabled</span><span style="color: blue">=&quot;True&quot;</span><span style="color: red"> Grid.Row</span><span style="color: blue">=&quot;1&quot;</span><span style="color: red"> Margin</span><span style="color: blue">=&quot;0,0,0,0&quot;</span> </li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: red"> ActiveContent</span><span style="color: blue">=&quot;{</span><span>Binding</span><span style="color: red"> ElementName</span><span style="color: blue">=Content1}&quot;</span><span style="color: red"> DocumentClosing</span><span style="color: blue">=&quot;DockManagerDocumentClosing&quot; &gt;</span></li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>ad</span><span style="color: blue">:</span><span>ResizingPanel</span><span style="color: red"> Orientation</span><span style="color: blue">=&quot;Horizontal&quot;&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>ad</span><span style="color: blue">:</span><span>DocumentPane</span><span style="color: red"> x</span><span style="color: blue">:</span><span style="color: red">Name</span><span style="color: blue">=&quot;DocumentHost&quot;&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;/</span><span>ad</span><span style="color: blue">:</span><span>DocumentPane</span><span style="color: blue">&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">&lt;/</span><span>ad</span><span style="color: blue">:</span><span>ResizingPanel</span><span style="color: blue">&gt;</span></li>
 <li><span style="color: blue">&lt;/</span><span>ad</span><span style="color: blue">:</span><span>DockingManager</span><span style="color: blue">&gt;</span></li>
 </ol></div></div>И DocumentContent для дочерних документов<br/>
<div style="color: black; font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span style="color: blue">&lt;</span><span>ad</span><span style="color: blue">:</span><span>DocumentContent</span><span style="color: red"> x</span><span style="color: blue">:</span><span style="color: red">Class</span><span style="color: blue">=&quot;DotNetNotepad.UI.Document&quot;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: red"> xmlns</span><span style="color: blue">=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: red"> xmlns</span><span style="color: blue">:</span><span style="color: red">x</span><span style="color: blue">=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: red"> xmlns</span><span style="color: blue">:</span><span style="color: red">mc</span><span style="color: blue">=&quot;http://schemas.openxmlformats.org/markup-compatibility/2006&quot;</span> </li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: red"> xmlns</span><span style="color: blue">:</span><span style="color: red">d</span><span style="color: blue">=&quot;http://schemas.microsoft.com/expression/blend/2008&quot;</span> </li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: red"> xmlns</span><span style="color: blue">:</span><span style="color: red">ad</span><span style="color: blue">=&quot;clr-namespace:AvalonDock;assembly=AvalonDock&quot;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: red"> xmlns</span><span style="color: blue">:</span><span style="color: red">avalonedit</span><span style="color: blue">=&quot;http://icsharpcode.net/sharpdevelop/avalonedit&quot;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: red"> mc</span><span style="color: blue">:</span><span style="color: red">Ignorable</span><span style="color: blue">=&quot;d&quot;</span><span style="color: red"> d</span><span style="color: blue">:</span><span style="color: red">DesignHeight</span><span style="color: blue">=&quot;300&quot;</span><span style="color: red"> d</span><span style="color: blue">:</span><span style="color: red">DesignWidth</span><span style="color: blue">=&quot;300&quot;&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>Grid</span><span style="color: red"> Background</span><span style="color: blue">=&quot;White&quot;&gt;</span></li>
 </ol></div></div>Полный листинг я приводить не буду, так как исходники всё равно опубликую, а загромождать кодом блог нет смысла.<br/>
После этих манипуляций, можно получить что то вроде вот этого<br/>
<div style="text-align: center"><!--noindex--><a href="https://lh6.googleusercontent.com/-M61AMAiHGt0/Tu956D32BpI/AAAAAAAAC4A/JMrGanv5TXU/s720/1.PNG" rel="nofollow" style="margin-left: 1em; margin-right: 1em"><img src="https://lh6.googleusercontent.com/-M61AMAiHGt0/Tu956D32BpI/AAAAAAAAC4A/JMrGanv5TXU/s720/1.PNG" width="720px" height="507px" border="0"/></a><!--/noindex--></div>Далее необходимо добавить главное меню. Там будет всего пара пунктов<br/>
<br/>
<div style="color: black; font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span style="color: blue">&lt;</span><span>Menu</span><span style="color: blue">&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>MenuItem</span><span style="color: red"> Header</span><span style="color: blue">=&quot;File&quot;&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>MenuItem</span><span style="color: red"> Header</span><span style="color: blue">=&quot;New&quot;</span> <span style="color: red"> Click</span><span style="color: blue">=&quot;NewClick&quot;&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;/</span><span>MenuItem</span><span style="color: blue">&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>MenuItem</span><span style="color: red"> Header</span><span style="color: blue">=&quot;Open&quot;</span> <span style="color: red"> Click</span><span style="color: blue">=&quot;OpenFileClick&quot;&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;/</span><span>MenuItem</span><span style="color: blue">&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>Separator</span><span style="color: blue">/&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>MenuItem</span><span style="color: red"> Header</span><span style="color: blue">=&quot;Exit&quot;</span> <span style="color: red"> Click</span><span style="color: blue">=&quot;ExitClick&quot;&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;/</span><span>MenuItem</span><span style="color: blue">&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">&lt;/</span><span>MenuItem</span><span style="color: blue">&gt;</span></li>
 <li><span style="color: blue">&lt;/</span><span>Menu</span><span style="color: blue">&gt;</span></li>
 </ol></div></div>Названия элементов говорят сами за себя. Следующий шаг - добавление с закладки текстового редактора. Это делается просто - сначала добавляем панель инструментов, потом сам редактор:<br/>
<br/>
<br/>
<div style="color: black; font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 2.5em; padding: 0 0 0 5px"><li><span style="color: blue">&lt;</span><span>ad</span><span style="color: blue">:</span><span>DocumentContent</span><span style="color: red"> x</span><span style="color: blue">:</span><span style="color: red">Class</span><span style="color: blue">=&quot;DotNetNotepad.UI.Document&quot;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: red"> xmlns</span><span style="color: blue">=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: red"> xmlns</span><span style="color: blue">:</span><span style="color: red">x</span><span style="color: blue">=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: red"> xmlns</span><span style="color: blue">:</span><span style="color: red">mc</span><span style="color: blue">=&quot;http://schemas.openxmlformats.org/markup-compatibility/2006&quot;</span> </li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: red"> xmlns</span><span style="color: blue">:</span><span style="color: red">d</span><span style="color: blue">=&quot;http://schemas.microsoft.com/expression/blend/2008&quot;</span> </li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: red"> xmlns</span><span style="color: blue">:</span><span style="color: red">ad</span><span style="color: blue">=&quot;clr-namespace:AvalonDock;assembly=AvalonDock&quot;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: red"> xmlns</span><span style="color: blue">:</span><span style="color: red">avalonedit</span><span style="color: blue">=&quot;http://icsharpcode.net/sharpdevelop/avalonedit&quot;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: red"> mc</span><span style="color: blue">:</span><span style="color: red">Ignorable</span><span style="color: blue">=&quot;d&quot;</span><span style="color: red"> d</span><span style="color: blue">:</span><span style="color: red">DesignHeight</span><span style="color: blue">=&quot;300&quot;</span><span style="color: red"> d</span><span style="color: blue">:</span><span style="color: red">DesignWidth</span><span style="color: blue">=&quot;300&quot;&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>Grid</span><span style="color: blue">&gt;</span></li>
 <li>&#160;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>Grid.RowDefinitions</span><span style="color: blue">&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>RowDefinition</span><span style="color: red"> Height</span><span style="color: blue">=&quot;32&quot;/&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>RowDefinition</span><span style="color: blue">/&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;/</span><span>Grid.RowDefinitions</span><span style="color: blue">&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>ToolBar</span><span style="color: red"> DockPanel.Dock</span><span style="color: blue">=&quot;Top&quot;&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>ToolBar.Resources</span><span style="color: blue">&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>Style</span><span style="color: red"> TargetType</span><span style="color: blue">=&quot;{</span><span>x</span><span style="color: blue">:</span><span>Type</span><span style="color: red"> Image}</span><span style="color: blue">&quot;&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>Style.Triggers</span><span style="color: blue">&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>DataTrigger</span><span style="color: red"> Binding</span><span style="color: blue">=&quot;{</span><span>Binding</span><span style="color: red"> RelativeSource</span><span style="color: blue">={</span><span>RelativeSource</span><span style="color: red"> AncestorType</span><span style="color: blue">={</span><span>x</span><span style="color: blue">:</span><span>Type</span><span style="color: red"> ButtonBase}</span><span style="color: blue">,</span><span style="color: red"> AncestorLevel</span><span style="color: blue">=</span>1}<span style="color: blue">,</span><span style="color: red"> Path</span><span style="color: blue">=IsEnabled}&quot;</span><span style="color: red"> Value</span><span style="color: blue">=&quot;False&quot;&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>Setter</span><span style="color: red"> Property</span><span style="color: blue">=&quot;Opacity&quot;</span><span style="color: red"> Value</span><span style="color: blue">=&quot;0.30&quot; /&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;/</span><span>DataTrigger</span><span style="color: blue">&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;/</span><span>Style.Triggers</span><span style="color: blue">&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;/</span><span>Style</span><span style="color: blue">&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;/</span><span>ToolBar.Resources</span><span style="color: blue">&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>Button</span><span style="color: red"> Click</span><span style="color: blue">=&quot;SaveFile&quot; &gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>Image</span><span style="color: red"> Source</span><span style="color: blue">=&quot;Images/Save.png&quot;</span><span style="color: red"> Height</span><span style="color: blue">=&quot;16&quot;/&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;/</span><span>Button</span><span style="color: blue">&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>Separator</span><span style="color: blue">/&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>Button</span><span style="color: red"> Command</span><span style="color: blue">=&quot;Cut&quot;&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>Image</span><span style="color: red"> Source</span><span style="color: blue">=&quot;Images/Cut.png&quot;</span><span style="color: red"> Height</span><span style="color: blue">=&quot;16&quot;/&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;/</span><span>Button</span><span style="color: blue">&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>Button</span><span style="color: red"> Command</span><span style="color: blue">=&quot;Copy&quot;&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>Image</span><span style="color: red"> Source</span><span style="color: blue">=&quot;Images/Copy.png&quot;</span><span style="color: red"> Height</span><span style="color: blue">=&quot;16&quot;/&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;/</span><span>Button</span><span style="color: blue">&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>Button</span><span style="color: red"> Command</span><span style="color: blue">=&quot;Paste&quot;&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>Image</span><span style="color: red"> Source</span><span style="color: blue">=&quot;Images/Paste.png&quot;</span><span style="color: red"> Height</span><span style="color: blue">=&quot;16&quot;/&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;/</span><span>Button</span><span style="color: blue">&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>Button</span><span style="color: red"> Command</span><span style="color: blue">=&quot;Delete&quot;&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>Image</span><span style="color: red"> Source</span><span style="color: blue">=&quot;Images/Delete.png&quot;</span><span style="color: red"> Height</span><span style="color: blue">=&quot;16&quot;/&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;/</span><span>Button</span><span style="color: blue">&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>Separator</span><span style="color: blue">/&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>Button</span><span style="color: red"> Command</span><span style="color: blue">=&quot;Undo&quot;&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>Image</span><span style="color: red"> Source</span><span style="color: blue">=&quot;Images/Undo.png&quot;</span><span style="color: red"> Height</span><span style="color: blue">=&quot;16&quot;/&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;/</span><span>Button</span><span style="color: blue">&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>Button</span><span style="color: red"> Command</span><span style="color: blue">=&quot;Redo&quot;&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>Image</span><span style="color: red"> Source</span><span style="color: blue">=&quot;Images/Redo.png&quot;</span><span style="color: red"> Height</span><span style="color: blue">=&quot;16&quot;/&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;/</span><span>Button</span><span style="color: blue">&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>Separator</span><span style="color: blue">/&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>CheckBox</span><span style="color: red"> IsChecked</span><span style="color: blue">=&quot;{</span><span>Binding</span><span style="color: red"> ElementName</span><span style="color: blue">=textEditor,</span><span style="color: red">Path</span><span style="color: blue">=WordWrap}&quot;&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>Image</span><span style="color: red"> Source</span><span style="color: blue">=&quot;Images/WordWrap.png&quot;</span><span style="color: red"> Height</span><span style="color: blue">=&quot;16&quot;/&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;/</span><span>CheckBox</span><span style="color: blue">&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>CheckBox</span><span style="color: red"> IsChecked</span><span style="color: blue">=&quot;{</span><span>Binding</span><span style="color: red"> ElementName</span><span style="color: blue">=textEditor,</span><span style="color: red">Path</span><span style="color: blue">=ShowLineNumbers}&quot;&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>TextBlock</span><span style="color: red"> Width</span><span style="color: blue">=&quot;16&quot;</span><span style="color: red"> TextAlignment</span><span style="color: blue">=&quot;Center&quot;&gt;</span><span>#</span><span style="color: blue">&lt;/</span><span>TextBlock</span><span style="color: blue">&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;/</span><span>CheckBox</span><span style="color: blue">&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>CheckBox</span><span style="color: red"> IsChecked</span><span style="color: blue">=&quot;{</span><span>Binding</span><span style="color: red"> ElementName</span><span style="color: blue">=textEditor,</span><span style="color: red">Path</span><span style="color: blue">=Options.ShowEndOfLine}&quot;&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>TextBlock</span><span style="color: red"> Width</span><span style="color: blue">=&quot;16&quot;</span><span style="color: red"> TextAlignment</span><span style="color: blue">=&quot;Center&quot;&gt;&#182;</span><span style="color: blue">&lt;/</span><span>TextBlock</span><span style="color: blue">&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;/</span><span>CheckBox</span><span style="color: blue">&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: green">&lt;!--Тут происходит биндинг вариантов подсветки синтаксиса, которые загружены в редактор--&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>ComboBox</span><span style="color: red"> Name</span><span style="color: blue">=&quot;highlightingComboBox&quot;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: red">SelectedItem</span><span style="color: blue">=&quot;{</span><span>Binding</span><span style="color: red"> SyntaxHighlighting</span><span style="color: blue">,</span><span style="color: red"> ElementName</span><span style="color: blue">=textEditor}&quot;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: red">ItemsSource</span><span style="color: blue">=&quot;{</span><span>Binding</span><span style="color: red"> Source</span><span style="color: blue">={</span><span>x</span><span style="color: blue">:</span><span>Static</span><span style="color: red"> avalonedit</span><span style="color: blue">:</span><span style="color: red">HighlightingManager</span><span style="color: blue">.Instance},</span><span style="color: red"> Path</span><span style="color: blue">=HighlightingDefinitions}&quot;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: red">SelectionChanged</span><span style="color: blue">=&quot;HighlightingComboBoxSelectionChanged&quot;/&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;/</span><span>ToolBar</span><span style="color: blue">&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: green">&lt;!--По умолчанию редактор настроен на подсветку XML--&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>avalonedit</span><span style="color: blue">:</span><span>TextEditor&#160;&#160;&#160;&#160;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: red"> x</span><span style="color: blue">:</span><span style="color: red">Name</span><span style="color: blue">=&quot;textEditor&quot;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: red"> FontFamily</span><span style="color: blue">=&quot;Consolas&quot;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: red"> FontSize</span><span style="color: blue">=&quot;10pt&quot;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: red"> ShowLineNumbers</span><span style="color: blue">=&quot;True&quot;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: red"> SyntaxHighlighting</span><span style="color: blue">=&quot;XML&quot;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: red">Grid.Row</span><span style="color: blue">=&quot;1&quot;&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>avalonedit</span><span style="color: blue">:</span><span>TextEditor.ContextMenu</span><span style="color: blue">&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>ContextMenu</span><span style="color: blue">&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>MenuItem</span><span style="color: red"> Command</span><span style="color: blue">=&quot;Cut&quot;</span><span style="color: red"> Header</span><span style="color: blue">=&quot;Cut&quot; /&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>MenuItem</span><span style="color: red"> Command</span><span style="color: blue">=&quot;Copy&quot;</span><span style="color: red"> Header</span><span style="color: blue">=&quot;Copy&quot; /&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>MenuItem</span><span style="color: red"> Command</span><span style="color: blue">=&quot;Paste&quot;</span><span style="color: red"> Header</span><span style="color: blue">=&quot;Paste&quot; /&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>MenuItem</span><span style="color: red"> Command</span><span style="color: blue">=&quot;Delete&quot;</span><span style="color: red"> Header</span><span style="color: blue">=&quot;Delete&quot; /&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>MenuItem</span><span style="color: red"> Command</span><span style="color: blue">=&quot;Undo&quot;</span><span style="color: red"> Header</span><span style="color: blue">=&quot;Undo&quot; /&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;</span><span>MenuItem</span><span style="color: red"> Command</span><span style="color: blue">=&quot;Redo&quot;</span><span style="color: red"> Header</span><span style="color: blue">=&quot;Redo&quot; /&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;/</span><span>ContextMenu</span><span style="color: blue">&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;/</span><span>avalonedit</span><span style="color: blue">:</span><span>TextEditor.ContextMenu</span><span style="color: blue">&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">&lt;/</span><span>avalonedit</span><span style="color: blue">:</span><span>TextEditor</span><span style="color: blue">&gt;</span></li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">&lt;/</span><span>Grid</span><span style="color: blue">&gt;</span></li>
 <li><span style="color: blue">&lt;/</span><span>ad</span><span style="color: blue">:</span><span>DocumentContent</span><span style="color: blue">&gt;</span></li>
 </ol></div></div>Следует пояснить назначение одного из обработчиков, указанных в листинге<br/>
<br/>
<div style="color: black; font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 3em; padding: 0 0 0 5px"><li><span style="color: grey">///</span><span style="color: green"> </span><span style="color: grey">&lt;summary&gt;</span></li>
 <li><span style="color: grey">///</span><span style="color: green"> Позволяет устанавливать стратегии разбиения текста на части</span></li>
 <li><span style="color: grey">///</span><span style="color: green"> </span><span style="color: grey">&lt;/summary&gt;</span></li>
 <li><span>FoldingManager</span> _foldingManager;</li>
 <li><span style="color: grey">///</span><span style="color: green"> </span><span style="color: grey">&lt;summary&gt;</span></li>
 <li><span style="color: grey">///</span><span style="color: green"> Сама стратегия разбиения</span></li>
 <li><span style="color: grey">///</span><span style="color: green"> </span><span style="color: grey">&lt;/summary&gt;</span></li>
 <li><span>AbstractFoldingStrategy</span> _foldingStrategy;</li>
 <li>&#160;</li>
 <li><span style="color: grey">///</span><span style="color: green"> </span><span style="color: grey">&lt;summary&gt;</span></li>
 <li><span style="color: grey">///</span><span style="color: green"> Обработчик меняет стратегию разбиения текста на части. Подсветка синтаксиса меняется автоматом.</span></li>
 <li><span style="color: grey">///</span><span style="color: green"> </span><span style="color: grey">&lt;/summary&gt;</span></li>
 <li><span style="color: grey">///</span><span style="color: green"> </span><span style="color: grey">&lt;param name=&quot;sender&quot;&gt;&lt;/param&gt;</span></li>
 <li><span style="color: grey">///</span><span style="color: green"> </span><span style="color: grey">&lt;param name=&quot;e&quot;&gt;&lt;/param&gt;</span></li>
 <li><span style="color: blue">void</span> HighlightingComboBoxSelectionChanged(<span style="color: blue">object</span> sender, <span>SelectionChangedEventArgs</span> e)</li>
 <li>{</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: green">// SyntaxHighlighting - это свойство, определяющее текущее правило подсветки синтаксиса</span></li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">if</span> (textEditor.SyntaxHighlighting == <span style="color: blue">null</span>)</li>
 <li>&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;_foldingStrategy = <span style="color: blue">null</span>;</li>
 <li>&#160;&#160;&#160;&#160;}</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">else</span></li>
 <li>&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">switch</span> (textEditor.SyntaxHighlighting.Name)</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">case</span> <span>&quot;XML&quot;</span>:</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;_foldingStrategy = <span style="color: blue">new</span> <span>XmlFoldingStrategy</span>();</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;textEditor.TextArea.IndentationStrategy = <span style="color: blue">new</span> ICSharpCode.AvalonEdit.Indentation.<span>DefaultIndentationStrategy</span>();</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">break</span>;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">case</span> <span>&quot;C#&quot;</span>:</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">case</span> <span>&quot;C++&quot;</span>:</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">case</span> <span>&quot;PHP&quot;</span>:</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">case</span> <span>&quot;Java&quot;</span>:</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;textEditor.TextArea.IndentationStrategy = <span style="color: blue">new</span> ICSharpCode.AvalonEdit.Indentation.CSharp.<span>CSharpIndentationStrategy</span>(textEditor.Options);</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;_foldingStrategy = <span style="color: blue">null</span>;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">break</span>;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">default</span>:</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;textEditor.TextArea.IndentationStrategy = <span style="color: blue">new</span> ICSharpCode.AvalonEdit.Indentation.<span>DefaultIndentationStrategy</span>();</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;_foldingStrategy = <span style="color: blue">null</span>;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">break</span>;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;}</li>
 <li>&#160;&#160;&#160;&#160;}</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">if</span> (_foldingStrategy != <span style="color: blue">null</span>)</li>
 <li>&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">if</span> (_foldingManager == <span style="color: blue">null</span>)</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;_foldingManager = <span>FoldingManager</span>.Install(textEditor.TextArea);</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;_foldingStrategy.UpdateFoldings(_foldingManager, textEditor.Document);</li>
 <li>&#160;&#160;&#160;&#160;}</li>
 <li>&#160;&#160;&#160;&#160;<span style="color: blue">else</span></li>
 <li>&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span style="color: blue">if</span> (_foldingManager != <span style="color: blue">null</span>)</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;{</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span>FoldingManager</span>.Uninstall(_foldingManager);</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;_foldingManager = <span style="color: blue">null</span>;</li>
 <li>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;}</li>
 <li>&#160;&#160;&#160;&#160;}</li>
 <li>}</li>
 </ol></div></div>После этих работ, блокнот стал выглядеть весьма привлекательно<br/>
<div style="text-align: center"><!--noindex--><a href="https://lh5.googleusercontent.com/-2unQ5hvaVOg/Tu9-BKpR02I/AAAAAAAAC4M/wVJ1ZlrRyWw/s576/2.PNG" rel="nofollow" style="margin-left: 1em; margin-right: 1em"><img src="https://lh5.googleusercontent.com/-2unQ5hvaVOg/Tu9-BKpR02I/AAAAAAAAC4M/wVJ1ZlrRyWw/s576/2.PNG" border="0"/></a><!--/noindex--></div>Однако, как оказалось, в AvalonEdit не встроена поддержка подсветки SQL и он не может автоматически распознать, подсветку чего включить при открытии файла. <br/>
Первая проблема решилась очень быстро - я просто погуглил, и нашел определение синтаксиса для SQL в одном из <!--noindex--><a href="http://minisqlquery.codeplex.com/SourceControl/changeset/view/50578#977605" rel="nofollow">проектов на кодеплексе</a><!--/noindex-->, и мне осталось лишь его встроить в редактор. <br/>
<div style="font-family: &quot;Courier New&quot;, Courier, Monospace; font-size: 10pt"><div><ol style="margin: 0 0 0 3em; padding: 0 0 0 5px"><li><span>&lt;?</span><span>xml</span><span> </span><span>version</span><span>=</span>&quot;<span>1.0</span>&quot;<span>?&gt;</span></li>
 <li><span>&lt;!--</span></li>
 <li><span>Copyright 2005-2009 Paul Kohler (http://pksoftware.net/MiniSqlQuery/). All rights reserved.</span></li>
 <li><span>This source code is made available under the terms of the Microsoft Public License (Ms-PL)</span></li>
 <li><span>http://minisqlquery.codeplex.com/license</span></li>
 <li><span>--&gt;</span></li>
 <li><span>&lt;</span><span>SyntaxDefinition</span><span> </span><span>name</span><span> = </span>&quot;<span>SQL</span>&quot;<span> </span><span>extensions</span><span> = </span>&quot;<span>.sql</span>&quot;<span>&gt;</span></li>
 <li> <span>&lt;</span><span>Properties</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>Property</span><span> </span><span>name</span><span>=</span>&quot;<span>LineComment</span>&quot;<span> </span><span>value</span><span>=</span>&quot;<span>--</span>&quot;<span>/&gt;</span></li>
 <li> <span>&lt;/</span><span>Properties</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>Digits</span><span> </span><span>name</span><span> = </span>&quot;<span>Digits</span>&quot;<span> </span><span>bold</span><span> = </span>&quot;<span>true</span>&quot;<span> </span><span>italic</span><span> = </span>&quot;<span>false</span>&quot;<span> </span><span>color</span><span> = </span>&quot;<span>Blue</span>&quot;<span>/&gt;</span></li>
 <li> <span>&lt;</span><span>RuleSets</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>RuleSet</span><span> </span><span>ignorecase</span><span> = </span>&quot;<span>true</span>&quot;<span>&gt;</span></li>
 <li> <span>&lt;</span><span>Delimiters</span><span>&gt;</span><span>&amp;amp;&amp;lt;&amp;gt;</span>~!%^*()-+=|\#/{}[]:;&quot;' , .?<span>&lt;/</span><span>Delimiters</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>Span</span><span> </span><span>name</span><span>=</span>&quot;<span>String</span>&quot;<span> </span><span>bold</span><span>=</span>&quot;<span>false</span>&quot;<span> </span><span>italic</span><span>=</span>&quot;<span>false</span>&quot;<span> </span><span>color</span><span>=</span>&quot;<span>Red</span>&quot;<span> </span><span>stopateol</span><span>=</span>&quot;<span>false</span>&quot;<span>&gt;</span></li>
 <li> <span>&lt;</span><span>Begin</span><span>&gt;</span>'<span>&lt;/</span><span>Begin</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>End</span><span>&gt;</span>'<span>&lt;/</span><span>End</span><span>&gt;</span></li>
 <li> <span>&lt;/</span><span>Span</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>Span</span><span> </span><span>name</span><span> = </span>&quot;<span>LineComment</span>&quot;<span> </span><span>bold</span><span> = </span>&quot;<span>false</span>&quot;<span> </span><span>italic</span><span> = </span>&quot;<span>false</span>&quot;<span> </span><span>color</span><span> = </span>&quot;<span>Green</span>&quot;<span> </span><span>stopateol</span><span> = </span>&quot;<span>true</span>&quot;<span>&gt;</span></li>
 <li> <span>&lt;</span><span>Begin</span><span>&gt;</span>--<span>&lt;/</span><span>Begin</span><span>&gt;</span></li>
 <li> <span>&lt;/</span><span>Span</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>Span</span><span> </span><span>name</span><span> = </span>&quot;<span>BlockComment</span>&quot;<span> </span><span>bold</span><span> = </span>&quot;<span>false</span>&quot;<span> </span><span>italic</span><span> = </span>&quot;<span>false</span>&quot;<span> </span><span>color</span><span> = </span>&quot;<span>Green</span>&quot;<span> </span><span>stopateol</span><span> = </span>&quot;<span>false</span>&quot;<span>&gt;</span></li>
 <li> <span>&lt;</span><span>Begin</span><span>&gt;</span>/*<span>&lt;/</span><span>Begin</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>End</span><span>&gt;</span>*/<span>&lt;/</span><span>End</span><span>&gt;</span></li>
 <li> <span>&lt;/</span><span>Span</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>KeyWords</span><span> </span><span>name</span><span>=</span>&quot;<span>JoinKeywords</span>&quot;<span> </span><span>bold</span><span>=</span>&quot;<span>true</span>&quot;<span> </span><span>italic</span><span>=</span>&quot;<span>false</span>&quot;<span> </span><span>color</span><span>=</span>&quot;<span>Purple</span>&quot;<span>&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>INNER</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>JOIN</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>LEFT</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>RIGHT</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>OUTER</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>UNION</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;/</span><span>KeyWords</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>KeyWords</span><span> </span><span>name</span><span>=</span>&quot;<span>AliasKeywords</span>&quot;<span> </span><span>bold</span><span>=</span>&quot;<span>false</span>&quot;<span> </span><span>italic</span><span>=</span>&quot;<span>false</span>&quot;<span> </span><span>color</span><span>=</span>&quot;<span>Maroon</span>&quot;<span>&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>AS</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;/</span><span>KeyWords</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>KeyWords</span><span> </span><span>name</span><span>=</span>&quot;<span>ComparisonKeywords</span>&quot;<span> </span><span>bold</span><span>=</span>&quot;<span>true</span>&quot;<span> </span><span>italic</span><span>=</span>&quot;<span>false</span>&quot;<span> </span><span>color</span><span>=</span>&quot;<span>Navy</span>&quot;<span>&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>AND</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>OR</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>LIKE</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;/</span><span>KeyWords</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>KeyWords</span><span> </span><span>name</span><span>=</span>&quot;<span>SpecializedKeywords</span>&quot;<span> </span><span>bold</span><span>=</span>&quot;<span>true</span>&quot;<span> </span><span>italic</span><span>=</span>&quot;<span>false</span>&quot;<span> </span><span>color</span><span>=</span>&quot;<span>Gray</span>&quot;<span>&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>TOP</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>LIMIT</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>OPENDATASOURCE</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>GO</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;/</span><span>KeyWords</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>KeyWords</span><span> </span><span>name</span><span>=</span>&quot;<span>DestructiveKeywords</span>&quot;<span> </span><span>bold</span><span>=</span>&quot;<span>true</span>&quot;<span> </span><span>italic</span><span>=</span>&quot;<span>false</span>&quot;<span> </span><span>color</span><span>=</span>&quot;<span>Red</span>&quot;<span>&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>DROP</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>DELETE</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>TRUNCATE</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;/</span><span>KeyWords</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>KeyWords</span><span> </span><span>name</span><span>=</span>&quot;<span>SqlKeywordsBold</span>&quot;<span> </span><span>bold</span><span>=</span>&quot;<span>true</span>&quot;<span> </span><span>italic</span><span>=</span>&quot;<span>false</span>&quot;<span> </span><span>color</span><span>=</span>&quot;<span>Blue</span>&quot;<span>&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>BEGIN</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>END</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>EXEC</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>CREATE</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>COMMIT</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>RAISERROR</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>ROLLBACK</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>TRAN</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>TRANSACTION</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>USE</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>USER</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>VIEW</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;/</span><span>KeyWords</span><span>&gt;</span></li>
 <li> <span>&lt;</span><span>KeyWords</span><span> </span><span>name</span><span>=</span>&quot;<span>SqlKeywordsNormal</span>&quot;<span> </span><span>bold</span><span>=</span>&quot;<span>false</span>&quot;<span> </span><span>italic</span><span>=</span>&quot;<span>false</span>&quot;<span> </span><span>color</span><span>=</span>&quot;<span>Blue</span>&quot;<span>&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>ADD</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>ALL</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>ANY</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>ASC</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>BETWEEN</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>BREAK</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>BY</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>CASCADE</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>CASE</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>CHECK</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>CHECKPOINT</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>CLOSE</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>COALESCE</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>COLLATE</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>COLUMN</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>COMPUTE</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>CONSTRAINT</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>CONTAINS</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>CONTINUE</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>CONVERT</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>CROSS</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>CURSOR</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>DECLARE</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>DEFAULT</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>DESC</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>DISTINCT</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>DOUBLE</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>ELSE</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>ESCAPE</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>EXCEPT</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>EXECUTE</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>EXISTS</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>EXIT</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>FETCH</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>FOR</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>FROM</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>FULL</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>FUNCTION</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>GOTO</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>GROUP</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>HAVING</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>IDENTITY</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>IDENTITY_INSERT</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>IDENTITYCOL</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>IF</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>IN</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>INSERT</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>INTO</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>IS</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>KEY</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>NOCHECK</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>NOT</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;<span>NULL</span>&quot;<span> /&gt;</span></li>
 <li> <span>&lt;</span><span>Key</span><span> </span><span>word</span><span>=</span>&quot;
