<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Блоги &#187; Andrey Gordienkov (Intel)</title>
	<atom:link href="http://software.intel.com/ru-ru/blogs/author/andrey-gordienkov/feed/" rel="self" type="application/rss+xml" />
	<link>http://software.intel.com/ru-ru/blogs</link>
	<description></description>
	<lastBuildDate>Thu, 24 May 2012 12:16:29 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.3</generator>
		<item>
		<title>Visual Studio. Шаблоны проектов</title>
		<link>http://software.intel.com/ru-ru/blogs/2010/05/06/visual-studio/</link>
		<comments>http://software.intel.com/ru-ru/blogs/2010/05/06/visual-studio/#comments</comments>
		<pubDate>Thu, 06 May 2010 10:23:41 +0000</pubDate>
		<dc:creator>Andrey Gordienkov (Intel)</dc:creator>
				<category><![CDATA[Разработка софта]]></category>
		<category><![CDATA[Microsoft* Visual Studio]]></category>

		<guid isPermaLink="false">http://software.intel.com/ru-ru/blogs/2010/05/06/visual-studio/</guid>
		<description><![CDATA[В последнее время я не просто много, а очень много экспериментирую с кодом, подходами, написаниями каких-то тестовых сценариев и приложений. Результат, конечно, всегда разный, ну да не об этом сегодня пойдет речь. Постепенно начинаешь уставать от настройки стандартных проектов. Для проекта библиотек надо удалить класс, создаваемый там по умолчанию, потому что все равно его будет [...]]]></description>
			<content:encoded><![CDATA[<p>В последнее время я не просто много, а очень много экспериментирую с кодом, подходами, написаниями каких-то тестовых сценариев и приложений. Результат, конечно, всегда разный, ну да не об этом сегодня пойдет речь. Постепенно начинаешь уставать от настройки стандартных проектов. Для проекта библиотек надо удалить класс, создаваемый там по умолчанию, потому что все равно его будет лень переименовывать. Мне приятно еще перенаправлять весь вывод компиляции в одну папку в корне всего проекта из всех библиотек, а не шариться по папкам ..\bin\Debug\ для каждого составляющего проекта, выгребать оттуда *.dll. Для проектов Test удаление ненужного барахла особенно актуально! Было бы неплохо еще сразу настроить атрибуты для сборки и информацию о ней (Assembly). Ко всему</p>
<p>Хочу, чтобы при создании чего-то нового, выбрал проект – и все у тебя настроено! И общая папка вывода, и нужные значения в AssemblyInfo прописаны, и лишнего ничего не валяется в проекте. Подумал я так и вспомнил, что есть у студии опция «Get online Templates», а раз есть онлайн, то должна быть и оффлайн – для моих собственных шаблонов. Сказано сделано!</p>
<p>В результате я очень доволен, что потратил час времени для настройки всех нужных мне проектов и теперь не отвлекаюсь в процессе, а только радуюсь, как все здорово вышло и что не надо тратить время на тупую работу.</p>
<p>О том, как это сделать в Visual Studio 2008, 2010 и пойдет речь дальше. Так же будет рассмотрено, как удалять, и импортировать готовые шаблоны проектов в студию.В последнее время я не просто много, а очень много экспериментирую с кодом, подходами, написаниями каких-то тестовых сценариев и приложений. Результат, конечно, всегда разный, ну да не об этом сегодня пойдет речь. Постепенно начинаешь уставать от настройки стандартных проектов. Для проекта библиотек надо удалить класс, создаваемый там по умолчанию, потому что все равно его будет лень переименовывать. Мне приятно еще перенаправлять весь вывод компиляции в одну папку в корне всего проекта из всех библиотек, а не шариться по папкам ..\bin\Debug\ для каждого составляющего проекта, выгребать оттуда *.dll. Для проектов Test удаление ненужного барахла особенно актуально! Было бы неплохо еще сразу настроить атрибуты для сборки и информацию о ней (Assembly). Ко всему</p>
<p>Хочу, чтобы при создании чего-то нового, выбрал проект – и все у тебя настроено! И общая папка вывода, и нужные значения в AssemblyInfo прописаны, и лишнего ничего не валяется в проекте. Подумал я так и вспомнил, что есть у студии опция «Get online Templates», а раз есть онлайн, то должна быть и оффлайн – для моих собственных шаблонов. Сказано сделано!</p>
<p>В результате я очень доволен, что потратил час времени для настройки всех нужных мне проектов и теперь не отвлекаюсь в процессе, а только радуюсь, как все здорово вышло и что не надо тратить время на тупую работу.</p>
<p>О том, как это сделать в Visual Studio 2008, 2010 можно <a href="http://softblog.violet-tape.ru/2010/05/06/visual-studio-templates/">почитать</a> у меня в <a href="http://softblog.violet-tape.ru/">блоге</a>. Так же будет рассмотрено, как удалять (что почти нигде не рассматривается =) Во время экспериментов у меня накопилось достаточно много мусора, который не совсем очевидно было как удалять), и импортировать готовые шаблоны проектов в студию.</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/ru-ru/blogs/2010/05/06/visual-studio/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Assembla</title>
		<link>http://software.intel.com/ru-ru/blogs/2010/03/25/assembla/</link>
		<comments>http://software.intel.com/ru-ru/blogs/2010/03/25/assembla/#comments</comments>
		<pubDate>Thu, 25 Mar 2010 10:48:38 +0000</pubDate>
		<dc:creator>Andrey Gordienkov (Intel)</dc:creator>
				<category><![CDATA[Intel Software Network]]></category>
		<category><![CDATA[Разработка софта]]></category>
		<category><![CDATA[Assembla]]></category>
		<category><![CDATA[Project management]]></category>
		<category><![CDATA[Repository]]></category>

		<guid isPermaLink="false">http://software.intel.com/ru-ru/blogs/2010/03/25/assembla/</guid>
		<description><![CDATA[Данный обзор не технический и не рекламная акция в пользу Assembla. Я лишь хочу поделиться опытом использования этого ресурса, насколько все просто и легко все организованно. Когда я более-менее стал писать программы, возникло желание делать это при любой возможности. Дома со стационарного компьютера, с ноутбука, с рабочего, да в целом с любого компьютера, где стоял [...]]]></description>
			<content:encoded><![CDATA[<p>Данный обзор не технический и не рекламная акция в пользу <a href="http://www.assembla.com" target="_blank">Assembla</a>. Я лишь хочу поделиться опытом использования этого ресурса, насколько все просто и легко все организованно.</p>
<p>Когда я более-менее стал писать программы, возникло желание делать это при любой возможности. Дома со стационарного компьютера, с ноутбука, с рабочего, да в целом с любого компьютера, где стоял подходящий IDE(Integrated Development Environment). Но тут всегда возникало несколько проблем:</p>
<ul>
<li>Как вести работу с последней версией кода</li>
<li>Как это потом синхронизировать с остальными компьютерами</li>
</ul>
<p>Первая проблема удручала меня в особенности. Так как когда выдавалась свободная минута на работе, или я хотел поработать с ноутбука, мне приходилось либо доставать версию с флешки, либо заниматься другим проектом. Если вдруг оказывалось, что я все же не забыл флешку и код, то возникала проблема номер два: как мне все это совместить и синхронизировать с остальными версиями проекта на других компьютерах.<br />
<span id="more-2003420"></span><br />
Я тогда еще много не знал, и мне казалось сказкой такая возможность. Т.е. я конечно о таком мечтал, но не очень знал с какой стороны к этому подойти.</p>
<p>В какой-то момент в любой ситуации и области знаний возникает переломный момент, после которого все разрозненные кусочки знаний складываются в единое целое. Я уже знал о динозавре Visual Source Safe (экспериментировал дома с доступами и все такое), пользовался активно Team Foundation Server на работе. Но надо было что-то такое, что было бы доступно отовсюду. Хотел было организовать себе статический IP адрес, но для физических лиц такой услуги у провайдера не было. И в этот момент, о чудо, попадается на глаза статья о сетевых сервисах предоставляющих системы контроля версий бесплатно, т.е. на халяву! Я уже не помню, какие системы были перечислены в той статье, но Assembla чем-то меня зацепила. Около полутора лет я пользуюсь этой системой и впечатления самые радужные. На своем отдельном <a href="http://softblog.violet-tape.ru/2010/02/25/assembla-overview/">блоге</a> я рассказываю об основных возможностях системы, таких как:</p>
<ul>
<li>Git, SVN репозитории;</li>
<li>Система управления требованиями;</li>
<li>Совместная работа над проектом;</li>
</ul>
<p>Помимо очевидных проблем с доступностью кода, возникала еще проблема с доступностью воспоминаний и прогресса по той или иной разработке. Бывало ведь такое, что пишешь, пишешь проект, а потом что-то случается и ты не имеешь возможности что-то делать там на протяжении месяца и более. После таких перерывов очень трудно вспомнить на чем ты остановился и какие еще фичи хотел сделать. Записывать это в каких-то файлах внесенных в проект, где-то еще на внешних ресурсах... не вариант. Тяжело вести, пользоваться, оторванность какая-то ощущается.<br />
В Assembla есть свой, весьма удобный менеджер задач (Agile Planner), который позволяет делать подзадачи, ссылки на задачи на одном уровне, обозначать майлстоуны. Причем во время коммита кода, в комментариях указываешь номер задачи с кодовым словом и статус задачи автоматически изменяется. Очень удобно! Вобщем в жизни теперь не забудешь о том, что делал и что хотел сделать. </p>
<p>Особенно сейчас радует наличие Git репозиториев в системе. Отчего я раньше проходил мимо - не знаю, но сейчас мне эта система нравится все больше и больше. </p>
<p>Вобщем, советую обратить внимание на данный ресурс! </p>
<p>Полные обзоры на <a href="http://softblog.violet-tape.ru">http://softblog.violet-tape.ru</a> </p>
<ul>
<li><a href="http://softblog.violet-tape.ru/2010/02/25/assembla-overview/">Assembla. Обзор</a></li>
<li><a href="http://softblog.violet-tape.ru/2010/03/02/assembla-collaborations/">Assembla. Совместная работа.</a></li>
</ul>
<p>Hard'n'Heavy! </p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/ru-ru/blogs/2010/03/25/assembla/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PostSharp. Альтернативы</title>
		<link>http://software.intel.com/ru-ru/blogs/2010/03/16/postsharp/</link>
		<comments>http://software.intel.com/ru-ru/blogs/2010/03/16/postsharp/#comments</comments>
		<pubDate>Tue, 16 Mar 2010 12:08:00 +0000</pubDate>
		<dc:creator>Andrey Gordienkov (Intel)</dc:creator>
				<category><![CDATA[Разработка софта]]></category>
		<category><![CDATA[AOP]]></category>
		<category><![CDATA[PostSharp]]></category>
		<category><![CDATA[Spring.Net]]></category>

		<guid isPermaLink="false">http://software.intel.com/ru-ru/blogs/2010/03/16/postsharp/</guid>
		<description><![CDATA[Я тут подумал, что несправедливо было бы обойти стороной сравнение PostSharp и других продуктов предоставляющих АОП. Ниже будут рассмотрены особенности использования, плюсы и минусы различных подходов. Но не думайте что PostSharp является серебрянной пулей. =) Можно почитать и википедию насчет АОП и фреймворков для .Net платформы. Я посмотрел несколько перечисленных там фреймворков лично и по [...]]]></description>
			<content:encoded><![CDATA[<p>Я тут подумал, что несправедливо было бы обойти стороной сравнение <a href="http://www.sharpcrafters.com" target="_blank">PostSharp</a> и других продуктов предоставляющих АОП. Ниже будут рассмотрены особенности использования, плюсы и минусы различных подходов. Но не думайте что PostSharp является серебрянной пулей. =)</p>
<p>Можно почитать и википедию насчет АОП и фреймворков для .Net платформы. Я посмотрел несколько перечисленных там фреймворков лично и по документированности и простоте использования остановился на PostSharp.</p>
<h2>Containers (Инверсия зависимостей)</h2>
<p>Большинство фреймворков направленных на инверсию зависимостей включают в себя некоторые возможности аспектно-ориентированного программирования. Для большинства достаточно простых технических требований, таких как трейсинг и обработка исключений применяемых к сервисам приложения, их возможностей хватает. Но их нельзя применить для более сложных и комплексных аспектов, которые могут применяться так же к объектам пользовательского интерфейса или к доменным объектам.</p>
<p><strong>Продукты</strong><strong>: </strong> <a href="http://www.springframework.net/" target="_blank">Spring.NET</a>, <a href="http://www.castleproject.org/" target="_blank">Castle Windsor</a>, <a href="http://msdn.microsoft.com/en-us/library/cc468366.aspx" target="_blank">Microsoft Unity</a><strong> </strong></p>
<p>Плюсы:</p>
<ul>
<li>Вы уже используете фреймворк для инверсии зависимостей</li>
<li>Аспекты могут быть настроены после сборки</li>
<li>Некоторые аспекты (трейсинг и обработка исключений) могут быть уже реализованы в вашем фреймворке.</li>
</ul>
<p>Минусы:</p>
<ul>
<li>Очень ограниченные возможности в плане АОП</li>
<li>Ваши объекты должны создаваться с помощью контейнера предоставляемого фреймворком. Такой способ нельзя применить для элементов пользовательского интерфейса, и во многих случаях для доменных объектов тоже.</li>
<li>Не работает со статическими, не публичными и/или не виртуальными методами. Так же не будет работать применение на поля, свойства и события классов.</li>
<li>Нет, или же плохое инструментирование для Visual Studio</li>
</ul>
<p><span id="more-2003341"></span></p>
<h2>Функциональное программирование</h2>
<p>Функциональное программирование (с помощью анонимных методов и лямбда выражений) может быть решением такой проблемы как автоматическое повторение действия при неудачно проведенной транзакции.</p>
<p>Плюсы:</p>
<ul>
<li>Стандартный С#. Не требуется никаких дополнительных зависимостей в вашей сборке.</li>
<li>Работа с уже знакомыми технологиями (я о анонимных методах и лямбда выражениях).</li>
<li>В некоторых случаях, результат по объему кода такой же малый как и с АОП.</li>
</ul>
<p>Минусы:</p>
<ul>
<li>Невозможно автоматически передать контекст из исполняемого кода в аспект. Например, у вас не получится реализовать трейсинг с помощью функционального программирования.</li>
<li>Придется дописывать код в каждый метод, к которому вы хотите добавить аспект. Настоящее АОП может применяться к множеству методов буквально одной строчкой кода и поддерживает сложные правила для выборки методов к применению.</li>
<li>Композиция аспектов получается менее удобная. Если у вас к одному и тому же методу применено два аспекта, и позже вы решили изменить порядок применения, то вам придется переписать все места, где вы их использовали.</li>
</ul>
<h2>Генерация кода</h2>
<p>АОП и генерация кода – это два неконкурирующих подхода в метапрограммировании. Генерация кода фокусируется на производстве нового кода основанного на указанных артефактах более высокого уровня абстракции. АОП особенно хорош в объединении кода бизнес логики и технического (инфраструктурного) кода.</p>
<p><strong>Продукты</strong><strong>: </strong>CodeSmith</p>
<p>Плюсы:</p>
<ul>
<li>Достаточно легко сгенерировать сложный участок кода, поскольку все разработчики работают с С# или VB.</li>
</ul>
<ul>
<li>Итоговый код на C#/VB может быть легко      открыт в Visual Studio и подвергнут дебагингу, как любой другой кусок      кода.</li>
</ul>
<p>Минусы:</p>
<ul>
<li>В отличие от АОП, исходники ответственные за генерацию другого кода обычно пишутся в виде XML файла.</li>
<li>Эта технология не может как бы то ни было подсовывать новые инструкции в существующий код или же модифицировать его поведение.</li>
</ul>
<h2>MSIL трансформация</h2>
<p>С ростом популярности PostSharp, авторы фреймворка предпринимали неоднократные попытки использовать трансформацию MSIL для добавления нового поведения в программы. Т.к. PostSharp сам по себе использует PostSharp SDK, то доступны самые продвинутые способы трансформации кода. Нет таких задач которые можно было бы реализовать на других платформах, а на PostSharp – нет.</p>
<p><strong>Продукты</strong><strong>:   <a href="http://www.mono-project.com/Cecil">Mono.Cecil</a></strong><strong>, <a href="http://ccimetadata.codeplex.com/" target="_blank">Microsoft.CCI</a></strong><strong>, <a href="http://ccisamples.codeplex.com/wikipage?title=CciSharp&amp;referringTitle=Home">CCISharp</a></strong><strong>.</strong></p>
<p>Плюсы:</p>
<ul>
<li>Устраняют зависимость от PostSharp.dll для времени исполнения программы (однако то же самое можно сделать с помощью PostSharp SDK)</li>
<li>Перечисленные фреймфорки бесплатны и за ними стоят большие компании.</li>
</ul>
<p>Минусы:</p>
<ul>
<li>Требуется продвинутое знание устройства и работы MSIL. Заметим, что используя MSIL в целом легко написать прототип, но в разы сложнее написать преобразование кода работающее в любых условиях.</li>
<li>Вы будете постоянно переизобретать колесо. Библиотеки преобразовании MSIL в общем случае низкоуровневые и они не предоставляют высокоуровневых плюшек имеющихся в арсенале PostSharp SDK.</li>
<li>Преобразования реализованные таким путем, как правило, плохо работают в композиции к одному и тому же методу.</li>
<li>Нет инструментов для Visual Studio.</li>
</ul>
<h2>Динамические языки</h2>
<p>Большинство динамических языков предоставляют возможность мета-программирования, которая позволяет вам модифицировать структуру и поведение программы в процессе ее исполнения. Можно использовать такое мета-программирование для выделения модулей проходящих сквозь слои приложения.</p>
<p>Плюсы:</p>
<ul>
<li>Мета-программирование на динамических языках просто, т.к. сами языки были придуманы для этого, это их основная направленность.</li>
</ul>
<p>Минусы:</p>
<ul>
<li>Придется полностью переключиться на динамический язык. А это не простой выбор.</li>
<li>Мета-программирование может оказаться слишком мощным инструментом для вас. Более знакомые подходы и инструменты все же предпочтительнее.</li>
<li>Нет инструментов для Visual Studio.</li>
</ul>
<h2>Сравнение технологий предоставляющих АОП</h2>
<h3>Где вы можете применить аспекты?</h3>
<table border="0" cellpadding="0">
<tbody>
<tr>
<td></td>
<td><strong>PostSharp<br />
MSIL transformation</strong></td>
<td><strong>Transparent Proxy<br />
Microsoft Unity</strong></td>
<td><strong>JIT-Emitted   Proxy<br />
Spring.NET, Castle Windsor</strong></td>
<td><strong>JIT-Emitted   Subclass<br />
Spring.NET, Castle Windsor</strong></td>
</tr>
<tr>
<td>Методы реализующие интерфейс</td>
<td><em>Да</em></td>
<td><em>Да</em></td>
<td><em>Да</em></td>
<td><em>Да</em></td>
</tr>
<tr>
<td>Виртуальные публичные методы</td>
<td><em>Да</em></td>
<td>Только с  MarshalByRefObject</td>
<td></td>
<td><em>Да</em></td>
</tr>
<tr>
<td>Не виртуальные публичные методы</td>
<td><em>Да</em></td>
<td>Только с  MarshalByRefObject</td>
<td></td>
<td><em>Да</em></td>
</tr>
<tr>
<td>Виртуальные защищенные методы</td>
<td><em>Да</em></td>
<td></td>
<td></td>
<td><em>Да</em></td>
</tr>
<tr>
<td>Все методы (включая private, protected, static)</td>
<td><em>Да</em></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Внешние методы (определенные в других сборках)</td>
<td><em>Да</em></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Конструкторы</td>
<td><em>Да</em></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Поля</td>
<td><em>Да</em></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Свойства</td>
<td><em>Да</em></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>События</td>
<td><em>Да</em></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<p>.</p>
<h3>Другие особенности</h3>
<table border="0" cellpadding="0">
<tbody>
<tr>
<td></td>
<td><strong>PostSharp<br />
MSIL transformation</strong></td>
<td><strong>Transparent Proxy<br />
Microsoft Unity</strong></td>
<td><strong>JIT-Emitted   Proxy<br />
Spring.NET, Castle Windsor</strong></td>
<td><strong>JIT-Emitted   Subclass<br />
Spring.NET, Castle Windsor</strong></td>
</tr>
<tr>
<td>Изменение аспекта после сборки</td>
<td></td>
<td><em>Да</em></td>
<td><em>Да</em></td>
<td><em>Да</em></td>
</tr>
<tr>
<td>Не влияет на время сборки</td>
<td></td>
<td><em>Да</em></td>
<td><em>Да</em></td>
<td><em>Да</em></td>
</tr>
<tr>
<td>Использование простого конструктора взамен фабрики</td>
<td><em>Да</em></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Поддержка Silverlight &amp; Compact Framework</td>
<td><em>Да</em></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<p>По материалам на сайте <a href="http://www.sharpcrafters.com" target="_blank">PostSharp</a>. Обожаю PostSharp! =)</p>
<p>Hard'n'heavy!</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/ru-ru/blogs/2010/03/16/postsharp/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PostSharp. Обзор. Часть I</title>
		<link>http://software.intel.com/ru-ru/blogs/2010/03/09/postsharp-i/</link>
		<comments>http://software.intel.com/ru-ru/blogs/2010/03/09/postsharp-i/#comments</comments>
		<pubDate>Tue, 09 Mar 2010 13:44:25 +0000</pubDate>
		<dc:creator>Andrey Gordienkov (Intel)</dc:creator>
				<category><![CDATA[Разработка софта]]></category>
		<category><![CDATA[AOP]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[PostSharp]]></category>

		<guid isPermaLink="false">http://software.intel.com/ru-ru/blogs/2010/03/09/postsharp-i/</guid>
		<description><![CDATA[Прежде чем перейти непосредственно к теме повествования, необходимо сказать несколько слов о системных вещах. Аспектно-Ориентированное программирование Аспектно-ориентированное программирование (АОП) — парадигма программирования, основанная на идее разделения функциональности для улучшения разбиения программы на модули. Существует достаточно много классов задач, решение которых невозможно в контексте ООП или же приведет к большой захламленности кода и связности модулей, что [...]]]></description>
			<content:encoded><![CDATA[<p>Прежде чем перейти непосредственно к теме повествования, необходимо сказать несколько слов о системных вещах.</p>
<h2>Аспектно-Ориентированное программирование</h2>
<p><em>Аспектно-ориентированное программирование (АОП)</em> — парадигма программирования, основанная на идее разделения функциональности для улучшения разбиения программы на модули.</p>
<p>Существует достаточно много классов задач, решение которых невозможно в контексте ООП или же приведет к большой захламленности кода и связности модулей, что плохо. Например, логирование. Для того чтобы вести лог работы программы, необходимо в каждый метод поместить несколько служебных строчек вызова службы логирования, так же возможно придется ее передавать через входные параметры методов. Весь этот код не будет относиться к выполнению реальной задачи возложенной на метод, а только мозолить глаза. К тому же, сколько лишних строчек кода придется написать вручную!</p>
<p>Еще примером может служить авторизация и проверка прав доступа. По-хорошему, перед началом выполнения важных методов, надо каждый раз проверять, имеет ли текущий пользователь права на запуск указанного метода. Тут тоже может быть очень много мороки и кода.</p>
<p>В целом, любой сквозной код выпадает из возможностей ООП. АОП программирование, наоборот, предоставляет все средства для выделения «сквозного кода» в отдельные сущности, что существенно упрощает код как для тестирования, так и для использования.</p>
<p><span id="more-2003278"></span></p>
<p>Основные понятия АОП:</p>
<ul>
<li><strong>Аспект</strong> (англ. aspect) — модуль или класс, реализующий сквозную функциональность. Аспект изменяет поведение остального кода, применяя совет в точках соединения, определённых некоторым срезом.</li>
<li><strong>Совет </strong>(англ. advice) — средство оформления кода, который должен быть вызван из точки соединения. Совет может быть выполнен до, после или вместо точки соединения.</li>
<li><strong>Точка соединения</strong> (англ. join point) — точка в выполняемой программе, где следует применить совет. Многие реализации АОП позволяют использовать вызовы методов и обращения к полям объекта в качестве точек соединения.</li>
<li><strong>Срез </strong>(англ. pointcut) — набор точек соединения. Срез определяет, подходит ли данная точка соединения к данному совету. Самые удобные реализации АОП используют для определения срезов синтаксис основного языка и позволяют их повторное использование с помощью переименования и комбинирования.</li>
<li><strong>Внедрение </strong>(англ. introduction, введение) — изменение структуры класса и/или изменение иерархии наследования для добавления функциональности аспекта в инородный код. Обычно реализуется с помощью некоторого метаобъектного протокола (англ. metaobject protocol, MOP).</li>
</ul>
<p>На этом можно перейти непосредственно к главной теме повествования.</p>
<h2>PostSharp</h2>
<p><a href="http://www.sharpcrafters.com" target="_blank">PostSharp</a> – это аспектно-ориентированный фреймворк, он привносит аспектно-ориентированное программирование на платформу .Net. С помощью PostSharp и АОП вы сможете выделить технические требования в отдельные сущности (аспекты).</p>
<ul>
<li>Технические требования реализовываются как простые C# классы.</li>
<li>Аспекты применяются к бизнес-объектам без изменения их исходного кода.</li>
<li>Во время сборки, аспекты внедряются в бизнес-объекты.</li>
</ul>
<p>Рассматриваемый фреймворк позволяет указывать к каким типам данных (классам, сборкам) применять аспекты, как осуществлять наследование аспектов и как они могут взаимодействовать друг с другом, очередность и множество других нюансов использования.</p>
<p>На данный момент официальный релиз есть у версии 1.5, версия 2.0 находится в стадии CTP или уже сильно RC. В основном речь пойдет о версии 1.5, но о вкусностях 2.0 я тоже не буду забывать и сообщать, где это требуется.</p>
<h2>Основные аспекты</h2>
<h3>OnMethodBoundary</h3>
<p>Аспект можно создать наследованием от класса <em>OnMethodBoundaryAspect </em>или от интерфейса <em>IOnMethodBoundaryAspect</em>.</p>
<p>Данный аспект применяется, когда у вас есть доступ к исходным кодам метода и вы хотите отслеживать события начала вызова метода, конец вызова, исключение и успешность завершения.  Все это делается переопределением методов <em>OnEntry</em>, <em>OnExit</em>, <em>OnException </em>и <em>OnSuccess </em>соответственно.</p>
<p>Схематически код после применения аспекта будет выглядеть так (естественно, это будет в закромах IL сборки)</p>
<pre name="code" class="C#">int MyMethod(object arg0, int arg1) {
    OnEntry();
    try {
        // Original method body.
        OnSuccess();
        return returnValue;
    }
    catch ( Exception e ) {
        OnException();
    }
    finally {
        OnExit();
    }
}</pre>
<p>На самом деле все выглядит более сложно, но для понимания это отличная иллюстрация. Объект типа <em>MethodExecutionEventArgs</em> передается во все 4 метода, и с помощью указанного объекта вы можете читать и писать значения в передаваемые параметры, получать текущее сообщение об ошибке, переопределять возвращаемое значение и изменять течение процедуры.</p>
<p>Доступ к параметрам осуществляется с помощью методов <em>GetReadOnlyArgumentArray</em>() и <em>GetWritableArgumentArray</em>() класса <em>MethodExecutionEventArgs</em>. Прошу заметить, что изменяться могут только те значения, которые передаются по ссылке. По большому счету оба метода возвращают один и тот же набор объектов, но в будущих версиях это поведение может измениться.</p>
<h3>OnFieldAccess</h3>
<p>Аспект можно создать наследованием от класса <em>OnFieldAccessAspect </em>или от интерфейса <em>IOnFieldAccessAspect</em>.</p>
<p>Применение данного аспекта позволяет перехватывать все операции чтения/записи для поля класса. Этот аспект имеет 2 метода для переопределения: <em>OnGetValue </em>и <em>OnSetValue</em>. Оба этих метода получают в качестве параметра класс <em>FieldAccessEventArgs</em>, который имеет 2 интересующих нас свойства <em>StoredValue </em>и <em>ExposedValue</em>. Первое позволяет получить доступ к реальному значению в поле, второе же играет роль буфера, при чтении там будет объект который будет возвращен, при записи, объект который пришел для записи.</p>
<p>Другими словами, реализация по умолчанию для <em>OnGetValue</em>:</p>
<pre>eventArgs.ExposedValue = eventArgs.StoredValue</pre>
<p>И  OnSetValue будет реализованно как:</p>
<pre>eventArgs.StoredValue = eventArgs.ExposedValue</pre>
<p>Более подробно о механизме действия аспекта этого будет в других статьях.</p>
<h3>OnMethodInvocation</h3>
<p>Аспект можно создать наследованием от класса <em>OnMethodInvocationAspect </em>или от интерфейса <em>IOnMethodInvocationAspect</em>.</p>
<p>Так же как и аспект <em>OnMethodBoundary</em>, рассматриваемый аспект позволяет добавить дополнительное поведение к методу. Разница в том, что этот аспект не модифицирует тело исходного метода, но перехватывает обращение и подменяет его собой, точнее тем, что будет написано в методе <em>OnInvocation</em>. Данный метод принимает в качестве параметра класс <em>MethodInvocationEventArgs </em>и самое интересное заключается в методе <em>Proceed</em>, который собственно и вызывает оригинальный метод. Реализация метода OnInvocation по умолчанию вызывает уже Proceed, таким образом не стоит еще раз вызывать этот метод если вы используете <em>base.OnInvocation</em>. И соответственно наоборот.</p>
<p>При работе с данным аспектом возможно получить доступ к исходному методу посредством свойства <em>Delegate</em>. Так же есть способ получить передаваемые параметры, вызвав метод <em>GetArgumentArray </em>у класса <em>MethodInvocationEventArgs</em>. Результатом будет массив объектов, которые можно менять на свой вкус. Итоговое значение надо записать в свойство <em>ReturnValue</em>.</p>
<pre>eventArgs.ReturnValue =  eventArgs.Delegate.DynamicInvoke( eventArgs.GetArgumentArray() );</pre>
<h3>OnException</h3>
<p>Аспект можно создать наследованием от класса <em>OnExceptionAspect </em>или от интерфейса <em>IOnExceptionAspect</em>.</p>
<p>Данный аспект добавляет обработчик исключений в метод, к которому применен аспект, что позволяет заключать код обработки исключений в отдельный атрибут, а не размазывать это все по классам.  В методе <em>GetExceptionType </em>можно определить какие типы исключений будут обрабатываться, если ничего не написать, то основной обработчик будет перехватывать все исключения. Сам же обработчик исключений будет в методе <em>OnException</em>. Пришедшее исключение будет доступно через свойство Exception (только для чтения) класса <em>MethodExecutionEventArgs</em>. Если нужно будет заменить исключение на какое-либо другое, надо создать новое исключение. Игнорирование исключений управляется через <em>СontrolFlow</em>.</p>
<h3>ImplementMethod</h3>
<p>Аспект можно создать наследованием от класса <em>ImplementMethod </em>или от интерфейса <em>IImplementMethod</em>.</p>
<p>Этот аспект позволяет разделить объявление и реализацию абстрактных и внешних методов. После применения этого аспекта на метод, он перестает быть абстрактным и получает реализацию определенную в аспетке в переопределенном методе <em>OnExecution </em>с параметром класса <em>MethodExecutionEventArgs</em>. С помощью этого класса можно получить доступ к самому методу (свойство <em>Method</em>) и к его аргументам (метод <em>GetWritableArgumentArray</em>()). Задать выходное значение можно с помощью свойства <em>ReturnValue</em>.</p>
<h3>Composition</h3>
<p>С помощью данного аспекта можно внедрять новые интерфейсы в существующий тип и отделять их реализацию в другие объекты. Композиция типов как правило считается более хорошим способом для реализации множественного наследования.</p>
<p>Что еще более важно, данный аспект может быть использован для автоматической реализации интерфейсов, чей код в целом повторяющийся и ничем не примечателен. Например как для интерфейса <em>INotifyPropertyChanged</em>.</p>
<p>Более подробно об этом аспекте пойдет речь в других статьях, тут много чего можно порассказать.</p>
<h2>Пример использования</h2>
<p>Допустим у вас есть большой и долгоиграющий проект с использованием многопоточности. Вдруг стала возникать трудноуловимая ошибка, которая не воспроизводится на вашей машине с дебаггером и вы принимаете решение залогировать все обращения к пространству имен System.Threading.</p>
<p>Для того, чтобы начать использовать PostSharp в вашем проекте, нужно добавить в список ссылок проекта две библиотеки PostSharp.Public.dll и PostSharp.Laos.dll.</p>
<p>Т.к. у нас будут логироваться методы не из наших сборок, то будем применять аспект <em>OnMethodInvocationAspect</em>.</p>
<pre name="code" class="C#">using System;
using PostSharp.Laos;

namespace PostSharp.Laos.Test {
    [Serializable]
    public class MyOnMethodInvocationAspect : OnMethodInvocationAspect {
        public override void OnInvocation(MethodInvocationEventArgs context) {
            Console.WriteLine("Calling {0}", context.Delegate.Method);
            context.Proceed();
        }
   }
}</pre>
<p>Аспекты <strong>всегда</strong> должны быть помечены как сериализуемые, это нужно в процессе выполнения кода и вставки во все нужные места программы, к тем методам и классам к которым вы применили аспект. Далее мы перегружаем метод <strong>OnInvocation</strong> в котором и делаем вывод имени метода на консоль.</p>
<p>Применить аспект можно следующим образом:</p>
<pre name="code" class="C#">[assembly: MyOnMethodInvocationAspect( AttributeTargetAssemblies = "mscorlib", AttributeTargetTypes = "System.Threading.*")]</pre>
<p>Эта строчка пишется в файле AssemblyInfo.cs для интересующей вас сборки. С помощью такого задания вам не придется приписывать аспект в миллионе мест вызова функций связанных с многопоточностью, аргумент <strong>AttributeTargetTypes</strong> позволяет указать, к чему применять аспект с помощью регулярных выражений.</p>
<p>В результате <a href="http://www.sharpcrafters.com" target="_blank">PostSharp</a> найдет все вызовы из пространства имен System.Threading и заменит их на вызов метода MyOnMethodInvocationAspect.Invoke. Естественно это будет на этапе компиляции приложения.</p>
<h2>Конец первой части</h2>
<p>В этой статье я рассказал о том, какие аспекты бывают и как они работают в целом. В следующих статьях я планирую более подробно остановиться на каждом из них. Рассказать, как аспекты могут взаимодействовать друг с другом, как ими можно управлять через атрибуты, как их применение можно валидировать во время компиляции. Какие новые штуки появились во второй версии этого фреймворка.</p>
<p>Hard’n’heavy!</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/ru-ru/blogs/2010/03/09/postsharp-i/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Установка самописных компонентов VS2008</title>
		<link>http://software.intel.com/ru-ru/blogs/2010/02/17/vs2008/</link>
		<comments>http://software.intel.com/ru-ru/blogs/2010/02/17/vs2008/#comments</comments>
		<pubDate>Wed, 17 Feb 2010 14:58:50 +0000</pubDate>
		<dc:creator>Andrey Gordienkov (Intel)</dc:creator>
				<category><![CDATA[Разработка софта]]></category>
		<category><![CDATA[Custom Controls]]></category>
		<category><![CDATA[VS2005]]></category>
		<category><![CDATA[VS2008]]></category>

		<guid isPermaLink="false">http://software.intel.com/ru-ru/blogs/2010/02/17/vs2008/</guid>
		<description><![CDATA[После того, как вы сделали собственные визуальные компоненты, я думаю, вы захотите их использовать в различных проектах, а впоследствии и поделится с миром наработками. Как их установить на панель инструментов в студии, как добавить эту библиотеку в “Add reference…” диалог и как избежать подводных камней в этом деле – все это будет описано в этой [...]]]></description>
			<content:encoded><![CDATA[<p>После того, как вы сделали собственные визуальные компоненты, я думаю, вы захотите их использовать в различных проектах, а впоследствии и поделится с миром наработками. Как их установить на панель инструментов в студии, как добавить эту библиотеку в “Add reference…” диалог и как избежать подводных камней в этом деле – все это будет описано в этой статье.</p>
<h2>Подготовка сборки (assembly)</h2>
<p>Когда у вас есть проект с настроенными компонентами и вы чувствуете что они выглядят и работают точно так как вам хочется – вы, возможно, захотите автоматизировать процесс установки. Для этого потребуется:</p>
<ol>
<li>Подписать сборку;</li>
<li>Установить сборку в GAC;</li>
<li>Добавить  в “Add reference…” диалог;</li>
<li>Добавить в панель инструментов студии.</li>
</ol>
<p>Далее я расскажу как автоматизировать почти все пункты из этого списка, в небольших примерах. Для дальнейшего повествования буду исходить их предположения, что библиотека с компонентами зовется <strong>myCustomControl.dll.</strong></p>
<p><span id="more-2003100"></span></p>
<p>Вообще, подписать сборку более чем легко. Вызываете контекстное меню для проекта, выбираете пункт Properties. Далее выбираем закладку Signing. Ставим галочку напротив “Sign the assembly” и выпадающий список будет доступен для редактирования.</p>
<p><a href="http://softblog.violet-tape.ru/wp-content/uploads/2010/01/InstallCustomControls001.png"><img class="alignnone size-full wp-image-179" src="http://softblog.violet-tape.ru/wp-content/uploads/2010/01/InstallCustomControls001.png" alt="" width="676" height="422" /></a></p>
<p>Выбираем пункт “<strong>&lt;New…&gt;</strong>”, заполняем поля в появившемся окне и жмем OK. Пересобираем приложение. Вот и все. Только что создали подпись (strong key) для сборки.</p>
<p>Следующим шагом будет…</p>
<h2>Добавление в GAC</h2>
<p>Думаю, что более подходящим способом будет использование утилиты gacutil.exe. Ее можно вызвать из Visual Studio Command Prompt следующим образом:</p>
<p><strong>gacutil /i “c:\my controls\myCustomControl.dll”</strong></p>
<p>Незабываем, что путь надо писать в кавычках, если он содержит пробелы. Эта операция добавит сборку в GAC. В нашем случае, в программе я использую ключ <strong>/if </strong>(install force) для того, чтобы переписать сборку, если она уже есть. Код ниже, автоматизирует вызов утилиты:</p>
<p>Gacutil распространяется с .NET SDK. Для версии 3.5 путь <em>C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\gacutil.exe</em>; 4.0 – <em>C:\Program Files\Microsoft SDKs\Windows\v7.0A\Bin\gacutil.exe</em>. Принимая во внимание только что сказанное:</p>
<pre name="code" class="C#">public class InstallToGac {
    public void Install(string fullAssemblyLocation) {
        var net35 = @"C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\gacutil.exe";
        var net40 = @"C:\Program Files\Microsoft SDKs\Windows\v7.0A\Bin\gacutil.exe";
        var value = File.Exists(net35)
                              ? net35
                              : File.Exists(net40)
                                    ? net40
                                    : "";
        if (value == "") return;
        var process = new Process();

        process.StartInfo.FileName = value;
        process.StartInfo.Arguments = string.Format("/if \"{0}\"", fullAssemblyLocation);
        process.StartInfo.CreateNoWindow = true;
        process.Start();
        process.WaitForExit();
    }
}</pre>
<p>В процессе выполнения может мелькнуть окно консоли и все. Сборка в GAC. Для того, чтобы удалить вашу библиотеку из GAC, надо выполнить команду с ключом  “<strong>/u</strong>” и добавить “<strong>f</strong>” если надо эту операцию сделать принудительно.</p>
<h2>Добавление в диалог “Add reference…” в Visual Studio</h2>
<p>Большинство моих коллег думают, что достаточно добавить библиотеку в GAC, как она тут же появится в вышеозначенном окне. К сожалению это не так, добавление в GAC это лишь один из шагов. Необходимо добавить еще ключ в реестре.</p>
<p>Цель:</p>
<p><strong>HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\AssemblyFolders</strong>.</p>
<p>По этому пути надо создать ключ с точно таким же именем, как и библиотека, но без dll. После всех действий должно получится как на картинке:</p>
<p><a href="http://softblog.violet-tape.ru/wp-content/uploads/2010/01/InstallCustomControls002.png"><img class="alignnone size-full wp-image-180" src="http://softblog.violet-tape.ru/wp-content/uploads/2010/01/InstallCustomControls002.png" alt="" width="595" height="236" /></a></p>
<p>Теперь, как это провернуть с помощью кода:</p>
<pre name="code" class="C#">public class InstallToRefLibrary {
     public void Install(string assemblyLocation, string dllName) {
         var p = @"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\AssemblyFolders";
         var key = string.Format("{0}\\{1}", p, dllName);
         var path = Registry.LocalMachine.OpenSubKey(p, true);

         if (path == null) return;

         path.SetValue(key, assemblyLocation);
         path.Close();
    }
}</pre>
<p>Для удаления – просто сотрите ключ из реестра.</p>
<h2>Добавление в панель инструментов Visual Studio</h2>
<p>Самые странные и уму непостижимые вещи начинаются здесь. Большинство из них из-за COM прошлого студии, некоторые появляются без вообще какого бы то ни было логического объяснения.  Ну ладно, начнем с дурацких ограничений, которые могут всплыть.</p>
<ul>
<li>Если у вас стоит <em>AnkhSVN</em>, то это может привести к СОМ ошибкам. Я пробовал создавать закладки для панели инструментов на Win7 (7100) и получал ошибку, пока не снес этот плагин для студии. Под ХР все работает отлично даже с AnkhSVN. Описанную проблему можно найти на форуме Infragistics – у них та же проблема с AnkhSVN; и на собственном форуме этого плагина, но без описания почему это происходит и есть ли какое-нибудь лекарство. Так что помните об этом.</li>
<li>Новая закладка с компонентами может быть установлена только тогда, когда <em>WinForm проект существует</em> в текущем открытом солюшене. Иначе только пустая закладка появится. К счастью, это легко обходится программным путем и я покажу как это сделать.</li>
</ul>
<p>Перед началом написания кода необходимо добавить проектные ссылки на:</p>
<ul>
<li>EnvDTE;</li>
<li>EnvDTE80;</li>
<li>EnvDTE90.</li>
</ul>
<p>От винта!</p>
<h2>Установка при запущенной студии</h2>
<p>В целом, при запущенной студии, достаточно легко работать. Для этого случая я буду предполагать, что солюшен с WinForm проектом все же существует и загружен. Ну или зачем тогда устанавливать визуальные компоненты? <img src='http://software.intel.com/ru-ru/blogs/wordpress/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>Первым делом надо определиться с тем, что мы будем устанавливать в новую панель, и новую панель тоже надо как-то идентифицировать. Для этой задачи создадим класс-помощник <strong>VSControl</strong>. Этот класс будет содержать информацию об имени новой панели, пути к сборке, типе компонента. Так же нам потребуется 2 конструктора: один для панели,</p>
<pre name="code" class="C#">public VSControl(string tabGroupName) {
    Control = null;
    AssemblyPath = "";
    TabName = tabGroupName;
    IsToolBoxTab = true;
}</pre>
<p>и второй для элементов на нем. Выглядит сложновато, но конечная цель – более легкий код в дальнейшем. Я думаю что тут можно избавиться от assemblyPath и использовать взамен assembly.Location.</p>
<pre name="code" class="C#">public VSControl(Assembly assembly, string assemblyPath, string typeName, string tabName) {
    var fullname = assembly.FullName.Split(new[] { ',' })[0];
    Control = assembly.GetType(fullname + "." + typeName);
    AssemblyPath = assemblyPath;
    TabName = tabName;
    IsToolBoxTab = false;
}</pre>
<p>Следующие действия:</p>
<ol>
<li>Получить ссылку на VS;</li>
<li>Получить ссылку на панель инструментов;</li>
<li>Создать новую панель;</li>
<li>Создать набор компонентов.</li>
</ol>
<p>Все эти действия, на мой взгляд, лучше всего собрать под крышей одного класса DevEnvironment. Этот класс будет иметь только один публичный метод, к примеру, <em>RegisterControls</em>, который будет принимать в качестве параметров массив компонентов и номер версии студии.</p>
<pre name="code" class="C#">public class DevEnvironment {
    public static bool RegisterControls(string dteVersion, params VSControl[] controls) { … }
}</pre>
<p>В деталях это все будет:</p>
<h3>Получить ссылку на VS</h3>
<p>Я предлагаю реализовать это как метод, который будет принимать <a href="http://msdn.microsoft.com/en-us/library/envdte.dte.aspx">DTE</a> (главный объект в модели автоматизации студии) версию и флаг, который будет показывать запущена студия или нет.</p>
<pre name="code" class="C#">(DTE2)Marshal.GetActiveObject("VisualStudio.DTE.9.0")</pre>
<p>Этот код применим для VS2008. Если вы захотите установить свои компоненты в несколько студий, я советую создать нумератор, где будут перечислены все возможные варианты.</p>
<pre name="code" class="C#">[Flags]
public enum DTEVersion {
     None = 0x0000,
     [Description("VisualStudio.DTE.9.0")]
     VS2008 = 0x0001,
     [Description("VisualStudio.DTE.8.0")]
     VS2005 = 0x0002,
     [Description("VisualStudio.DTE.7.0")]
     VS2003 = 0x0004,
     [Description("VisualStudio.DTE.10.0")]
     VS2010 = 0x0008,
}</pre>
<p>Использование нумераторов делает код более гибким. Можно не делать проверку на соответствие строк, к тому же RegisterControls так же может принимать DTEVersion. Внутри метода RegisterControls можно будет написать тогда так:</p>
<pre name="code" class="C#">public static void RegisterControls(DTEVersion dteVersion, params VSControl[] controls) {
    DTE2 dte = null;
    var alreadyCreated = false;

    if ((dteVersion &amp; DTEVersion.VS2008) &gt; DTEVersion.None) {
        dte = (DTE2)Marshal.GetActiveObject("VisualStudio.DTE.9.0");
        // other code
        ...
    }

    if ((dteVersion &amp; DTEVersion.VS2010) &gt; DTEVersion.None) {
        dte = (DTE2)Marshal.GetActiveObject("VisualStudio.DTE.10.0");
        // other code
       ...
    }
}</pre>
<p>Появление в коде строковых переменных весьма странно, когда уже есть нумератор с описаниями. И вот способ как это можно использовать:</p>
<pre name="code" class="C#">internal static string GetEnumDescription(Enum value) {
    var fieldInfo = value.GetType().GetField(value.ToString());
    var attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
    return (attributes.Length &gt; 0) ? attributes[0].Description : value.ToString();
}</pre>
<p>И тогда получение ссылки на студию</p>
<pre name="code" class="C#">dte = (DTE2)Marshal.GetActiveObject("VisualStudio.DTE.9.0");</pre>
<p>можно переписать следующим образом:</p>
<pre name="code" class="C#">dte = GetDesignTimeEnvironment(DTEVersion.VS2008, ref alreadyCreated);</pre>
<p>в новом методе мы проверим еще кое-что. Когда вы получаете DTE2, это занимает некоторое время для того, чтобы СОМ-метод вызвался и вернул результат. После этого, было бы неплохо проверить, что ссылка на студию действительно получена, и попробовать переключится на какой-нибудь базовый экран, к примеру, на окно свойств.</p>
<pre name="code" class="C#">public static DTE2 GetDesignTimeEnvironment(DTEVersion dteVersion, ref bool alreadyCreated) {
    alreadyCreated = false;

    var progID = GetEnumDescription(dteVersion);
    DTE2 result;

    try {
        result = (DTE2)Marshal.GetActiveObject(progID);
        Thread.Sleep(5000);
        try {
             result.ExecuteCommand("View.PropertiesWindow", "");
             alreadyCreated = true;
        }
        catch  {
             result = null;
        }
    }
    catch {   //There is no open VS.Net
        result = null;
    }

    return result;
}</pre>
<p>Осталось проверить результат на null и если не null, то создаем новую панель.</p>
<h3>Получение указателя на панель инструментов</h3>
<p>Вы будете удивлены, но это очень легко! Всего 2 строчки кода.</p>
<pre name="code" class="C#">var toolbox = dte.Windows.Item(Constants.vsWindowKindToolbox);
var tabs = ((ToolBox)toolbox.Object).ToolBoxTabs;</pre>
<h3>Создание новой панели</h3>
<p>Так как компоненты и новая панель уже должны быть обернуты в VSControl – новый метод должен принимать массив этого класса. Ищем в массиве объявления панелей и создаем их.</p>
<pre name="code" class="C#">internal static void RegisterControls(DTE2 dte, bool alreadyCreatedDTE, VSControl[] controls) {
    var toolbox = dte.Windows.Item(Constants.vsWindowKindToolbox);
    var tabs = ((ToolBox)toolbox.Object).ToolBoxTabs;
    controls
        .ToList()
        .FindAll(i =&gt; i.IsToolBoxTab)
        .ForEach(i =&gt; {
                 if (GetToolBoxTab(tabs, i.TabName) == null)
                 tabs.Add(i.TabName);
                 });
}

private static ToolBoxTab3 GetToolBoxTab(ToolBoxTabs tabs, string tabName) {
    foreach (ToolBoxTab3 tab in tabs) {
        if (smenglish.CompareInfo.Compare(tab.Name, tabName,  CompareOptions.IgnoreCase) == 0)
            return tab;
    }

    return null;
}</pre>
<p>И поле класса:</p>
<pre name="code" class="C#">internal static CultureInfo smenglish = CultureInfo.CreateSpecificCulture("en");</pre>
<h3>Создание новых компонентов</h3>
<p>Теперь, когда созданы панели для новых компонентов, время создать реальные объекты. Для этого надо активировать соответствующую панель и создать элемент. Тоже не тяжело. Добавляем этот код после создания панелей.</p>
<pre name="code" class="C#">foreach (var control in controls) {
    var tab = GetToolBoxTab(tabs, control.TabName);

    if (tab != null &amp;&amp; !control.IsToolBoxTab) {
        tab.Activate();
        tab.ToolBoxItems.Add("anyName", control.Control, vsToolBoxItemFormat.vsToolBoxItemFormatDotNETComponent);
    }
}</pre>
<p>Здесь есть небольшие нюансы: когда добавляете новый элемент с помощью кода <em>tab.ToolBoxItems.Add</em>, второй параметр – объект. Если передать строку, то она будет распознана как путь до сборки и все публичные компоненты оттуда будут добавлены. Если передать тип, то только этот объект будет добавлен.</p>
<p>Когда программа закончит добавлять компоненты к панели(ям), надо будет закрыть соединение c DTE2.</p>
<pre name="code" class="C#">dte.Quit();</pre>
<p>Вот и всё, для случая запущенной студии.</p>
<h2>Установка при незапущенной студии</h2>
<p>Думаю, что вам не захочется просить пользователя запустить Visual Studio и создать проект WinForm, перед тем как запустить установщик. И далее будет описано, как сделать это все автоматически.</p>
<p>Для начала нам надо создать новый экземпляр студии, для того чтобы продолжить работу. Думаю, что лучшим местом для этого куска кода будет метод <em>GetDesignTimeEnvironment</em>.</p>
<pre name="code" class="C#">if (result == null) {
    //Open a new VS.Net
    var type = Type.GetTypeFromProgID(progID);

    result = (DTE2) Activator.CreateInstance(type, true);
}</pre>
<p>Как я уже ранее говорил, необходимо создать WinForm проект для того, чтобы все нормально установить. И это возможно сделать кодом тоже. Открываем метод <em>RegisterControls</em> и добавляем в начало.</p>
<pre name="code" class="C#">if (!alreadyCreatedDTE) {
     var tmpFile = Path.GetFileNameWithoutExtension(Path.GetTempFileName());
     var tmpDir = string.Format("{0}{1}", Path.GetTempPath(), tmpFile);
     var solution = dte.Solution as Solution2;
     var templatePath = solution.GetProjectTemplate("WindowsApplication.zip", "CSharp");

     solution.AddFromTemplate(templatePath, tmpDir, "dummyproj", false);
}</pre>
<p>На мой взгляд код тут самодокументирующийся и в комментариях не нуждается. Но не забываем закрыть солюшен перед концом программы.</p>
<pre name="code" class="C#">dte.Solution.Close(false);</pre>
<p>Параметр является ответом на вопрос, сохранять проект или нет.</p>
<p>Теперь новые компоненты будут установлены независимо от того, запущена студия или нет. К сожалению СОМ ошибки могут нарушить всю идиллию. Во время разработки я получал тонны ошибок, которые сообщали, что СОМ-объект все еще занят и не может быть вызван. Поиски в интернете дали ответ на то, как это избежать.</p>
<h2>Как избежать СОМ ошибок</h2>
<p>Основная идея в том, чтобы отфильтровывать сообщения от СОМ-объектов и получать только те, на которые мы подпишемся.</p>
<p>Необходимо объявить интерфейс <strong>IOleMessageFilter</strong></p>
<pre name="code" class="C#">[ComImport, Guid("00000016-0000-0000-C000-000000000046"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IOleMessageFilter {
    [PreserveSig]
    int HandleInComingCall(
            int dwCallType,
            IntPtr hTaskCaller,
            int dwTickCount,
            IntPtr lpInterfaceInfo);

    [PreserveSig]
    int RetryRejectedCall(
            IntPtr hTaskCallee,
            int dwTickCount,
            int dwRejectType);

    [PreserveSig]
    int MessagePending(
           IntPtr hTaskCallee,
           int dwTickCount,
           int dwPendingType);
}</pre>
<p>И сделать реализацию к нему.</p>
<pre name="code" class="C#">public class MessageFilter : IOleMessageFilter {
    //
    // Class containing the IOleMessageFilter
    // thread error-handling functions.
    // Start the filter.

    public static void Register() {
        IOleMessageFilter newFilter = new MessageFilter();
        IOleMessageFilter oldFilter = null;
        CoRegisterMessageFilter(newFilter, out oldFilter);
    }

    // Done with the filter, close it.

    public static void Revoke() {
        IOleMessageFilter oldFilter = null;
        CoRegisterMessageFilter(null, out oldFilter);
    }

    //
    // IOleMessageFilter functions.
    // Handle incoming thread requests.
    int IOleMessageFilter.HandleInComingCall(int dwCallType, IntPtr hTaskCaller, int dwTickCount, IntPtr lpInterfaceInfo) {
        //Return the flag SERVERCALL_ISHANDLED.
        return 0;
    }

    // Thread call was rejected, so try again.
    int IOleMessageFilter.RetryRejectedCall(IntPtr hTaskCallee, int dwTickCount, int dwRejectType) {
        if (dwRejectType == 2) {
            // flag = SERVERCALL_RETRYLATER.
            // Retry the thread call immediately if return &gt;=0 &amp;
            // &lt;100.
            return 99;
        }

       // Too busy; cancel call.
       return -1;
    }

    int IOleMessageFilter.MessagePending(IntPtr hTaskCallee, int dwTickCount, int dwPendingType) {
        //Return the flag PENDINGMSG_WAITDEFPROCESS.
        return 2;
    }

    // Implement the IOleMessageFilter interface.
    [DllImport("Ole32.dll")]
    private static extern int
         CoRegisterMessageFilter(IOleMessageFilter newFilter, out IOleMessageFilter oldFilter);
    }</pre>
<p>В итоге должно получиться что-то в духе:</p>
<pre name="code" class="C#">MessageFilter.Register();
RegisterControls(dte, alreadyCreated, controls);
MessageFilter.Revoke();</pre>
<p>С этим кодом все у вас будет в ажуре!  =)</p>
<p>Я тестировал на семерке, ХР и все работало замечательно. Я надеюсь получить ваши комментарии, вопросы, предложения. Кстати да, в процессе написания я заметил места, где можно улучшить код, но оставил его до лучших времен.</p>
<p><a href="http://softblog.violet-tape.net/download/InstallCustomControl.zip" target="_blank">Source code</a></p>
<p>Hard’n’heavy!</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/ru-ru/blogs/2010/02/17/vs2008/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Smart tag – Single Binding</title>
		<link>http://software.intel.com/ru-ru/blogs/2010/01/21/smart-tag-single-binding/</link>
		<comments>http://software.intel.com/ru-ru/blogs/2010/01/21/smart-tag-single-binding/#comments</comments>
		<pubDate>Thu, 21 Jan 2010 12:15:35 +0000</pubDate>
		<dc:creator>Andrey Gordienkov (Intel)</dc:creator>
				<category><![CDATA[Intel Software Network]]></category>
		<category><![CDATA[Разработка софта]]></category>
		<category><![CDATA[Custom Controls]]></category>
		<category><![CDATA[Smart Tag]]></category>

		<guid isPermaLink="false">http://software.intel.com/ru-ru/blogs/2010/01/21/smart-tag-single-binding/</guid>
		<description><![CDATA[Продолжаем разговор на тему «Как создать смарт тэг». В предыдущем посте на эту тему я рассказал, что такое смарт тэги и с чем их едят. Сейчас же я хочу рассказать о том, как сделать биндинг для единичного поля.

В дальнейшем повествовании я буду исходить из предположения, что у вас уже есть свой компонент, к нему применены все заготовки для создания смарт тэга и все готово для дальнейших действий. Так же как и в прошлом посте, я советую использовать ReSharper.

Я собираюсь рассказать и показать, как создать такую же функциональность в смарт тэге, которую вы наблюдаете при задании биндинга в окне свойств.]]></description>
			<content:encoded><![CDATA[<h2>Intro</h2>
<p>Продолжаем разговор на тему «Как создать смарт тэг». В предыдущем посте на эту тему я рассказал, что такое смарт тэги и с чем их едят. Сейчас же я хочу рассказать о том, как сделать биндинг для единичного поля.</p>
<p>В дальнейшем повествовании я буду исходить из предположения, что у вас уже есть свой компонент, к нему применены все заготовки для создания смарт тэга и все готово для дальнейших действий. Так же как и в прошлом посте, я советую использовать ReSharper.</p>
<p>Я собираюсь рассказать и показать, как создать такую же функциональность в смарт тэге, которую вы наблюдаете при задании биндинга в окне свойств.</p>
<p><a href="http://softblog.violet-tape.ru/wp-content/uploads/2010/01/001.png"><img class="alignnone size-full wp-image-170" src="http://softblog.violet-tape.ru/wp-content/uploads/2010/01/001.png" alt="" width="382" height="302" /></a></p>
<p>Реализовав этот функционал, вы сможете сэкономить много времени, которое раньше тратилось на путешествия по окну свойств для того, чтобы настроить поведение компонента.</p>
<p><span id="more-2002994"></span></p>
<h2>Есть ли стандартный способ задания биндинга?</h2>
<p>Я его не нашел. Поиски «простого» и короткого стандартного способа не увенчались успехом. Sad, but true. Используя гугл, я нашел только 4 (четыре) вопроса по теме, и те без ответов. Только раз было направление для поисков, но для Web форм. Расстройству моему не было предела, но недолго оно длилось! Если кто-то что-то смог сделать, то другой человек может это сделать тоже. Руководствуясь этим железобетонным принципом, я вспомнил, что Microsoft опубликовала исходные коды для .Net фреймворка и потратив некоторое время на поиски я нашел где их слить и начал детальное исследование.</p>
<p>Используя свои знания по разработке компонентов и опыту работы с ними, я начал поиски с реализации ComboBox, чтобы посмотреть какой дизайнер используется для биндинга. К сожалению, там не оказалось какого-то общего дизайнера который можно было бы сразу прикрутить и получить профит. Но в целом это не было проблемой. Я нашел такие строчки:</p>
<pre name="code" class="c#">[TypeConverter("System.Windows.Forms.Design.DesignBindingConverter"),
Editor("System.Windows.Forms.Design.DesignBindingEditor, System.Design", typeof (UITypeEditor))]</pre>
<p>Можете <a href="http://social.msdn.microsoft.com/Search/en-US?query=DesignBindingEditor&amp;ac=8" target="_blank">поискать</a> в MSDN что пишут по поводу DesignBindingEditor в общем поиске и по коду. Что?  А? Пишут, что ничего нет?</p>
<p>Ну ладно, редактор и конвертор типов должны все равно быть стандартными и найти их проблемой быть не должно. Но это не все, иначе было бы слишком легко! ))</p>
<h2>Копи-паста</h2>
<p>Это наш путь к пониманию сути вещей (если нет документации). Скопировать, вставить, немного менять код и смотреть как и что меняется. Да, метод научного тыка.</p>
<p>Как вы должны помнить, свойства, объявленные в классе дизайнера смарт тэга, будут потом использоваться для отображения пользователю и весь рабочий код помещается в “get”/“set”. Здесь много всего написано, что даже чуток пугает. =)</p>
<pre name="code" class="c#">public object BoundSelectedValue {
    get {
        System.Windows.Forms.Binding b = GetSelectedValueBinding();
        string dataMember;
        object dataSource;
        if (b == null) {
            dataMember = null;
            dataSource = null;
        } else {
            dataMember = b.BindingMemberInfo.BindingMember;
            dataSource = b.DataSource;
        }
        string typeName = string.Format(System.Globalization.CultureInfo.InvariantCulture,  "System.Windows.Forms.Design.DesignBinding, {0}", typeof(ControlDesigner).Assembly.FullName);
        _boundSelectedValue = TypeDescriptor.CreateInstance(null, Type.GetType(typeName), new Type[] { typeof(object), typeof(string) }, new object[] { dataSource, dataMember });
        return _boundSelectedValue;
    }
set {
    if (value is String) {
        PropertyDescriptor pd = TypeDescriptor.GetProperties(this)["BoundSelectedValue"];
        TypeConverter tc = pd.Converter;
        _boundSelectedValue = tc.ConvertFrom(new EditorServiceContext(_owner), System.Globalization.CultureInfo.InvariantCulture, value);
    } else {
       _boundSelectedValue = value;
       if (value != null) {
           object dataSource = TypeDescriptor.GetProperties(_boundSelectedValue)["DataSource"].GetValue(_boundSelectedValue);
           string dataMember = (string)TypeDescriptor.GetProperties(_boundSelectedValue)["DataMember"].GetValue(_boundSelectedValue);
SetSelectedValueBinding(dataSource, dataMember);
        }
      }
   }
}</pre>
<p>Вау!</p>
<p>Начнем разбор полетов со свойства «get». В строке номер 3 берутся все элементы составляющие компонент и ищутся биндинги с необходимыми именами. Для ComboBox это будет SelectedValue. Если ничего не найдено, значит биндинг еще не назначался на данное поле. Иначе, с помощью DesighnBindingConverter, берутся свойства dataMember и dataSource для создания строкового представления биндинга.</p>
<p>В результате экспериментов «get» оказался легкой частью для адаптации. Больше всего проблем возникло с «set». Если биндинг был уже назначен, то он в смарт тэге представлялся в виде строки, которую надо было разобрать (распарсить). Для этого использовалась первая часть выражения if. И в этой части, мне кажется и кроется причина почему же биндиг одиночного поля не опубликован в свободном доступе. В строке номер 21 создается EditorServiceContext, который является внутренним классом в .Net. Придется его найти и «переписать» для наших нужд. Все переписывание конечно свелось к копи-пасте в локальный проект. Последнее выражение с SetSelectedValueBinding так же было скопировано без изменений.</p>
<h2>Рефакторинг</h2>
<p>Оставлять такую прорву кода как есть не хотелось, тем более трудно было бы создать еще одно свойство с биндингом. Так что я переделал код на более короткую запись. Получилось в итоге вот так:</p>
<pre name="code" class="c#">[TypeConverter("System.Windows.Forms.Design.DesignBindingConverter"),
Editor("System.Windows.Forms.Design.DesignBindingEditor, System.Design", typeof (UITypeEditor))]
public object DefBindProperty {
    get { return GetBind("DefBind"); }
    set { SetBind("DefBind", value, "DefBindProperty"); }
}</pre>
<p>Получилось более ясно и просто. Можно использовать не задумываясь для других компонентов. В данном случае первый параметр указывает на свойство в связанном со смарт тэгом компоненте.</p>
<p>GetBind и SetBind объявлены в классе ControlActionListBase. Э том случае ActionList наследуем от ControlActionListBase, а ControlActionListBase от DesignerActionList.</p>
<pre name="code" class="c#">public class MyControlActionList : ControlActionListBase { … }

public class ControlActionListBase : DesignerActionList { … }</pre>
<p>Таким образом, в нашем классе MyControlActionList остаются только значимый код для конкретного смарт тэга, что упростит дальнейшую редакцию и чтение. Весь служебный, общий код вынесен в базу. Написал и забыл. <img src='http://software.intel.com/ru-ru/blogs/wordpress/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  Когда вы примените биндинг с помощью описанного кода через смарт тэг, в экземпляре компонента будет сгенерирован код похожий на этот:</p>
<pre name="code" class="c#">this.myControl1.DataBindings.Add(new System.Windows.Forms.Binding("DefBind", this.bindingSource, "StringField", true));</pre>
<p>Все по-честному!</p>
<p>Финальный результат можно посмотреть в <a href="http://softblog.violet-tape.net/download/Smart_Tag_-_Simple.zip" target="_blank">исходниках</a>.</p>
<p>На данном этапе вы можете создавать свои компоненты и расширять уже существующие с биндингом на единичное поле, а не список. Я надеюсь, что это ускорит время разработки приложений.</p>
<p>Статья на <a href="http://softblog.violet-tape.ru/2010/01/06/smart-tag-single-binding/">Violet tape</a>, подписаться на <a href="http://feeds.feedburner.com/VioletTapeRu">RSS</a></p>
<p>Hard’n’heavy!</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/ru-ru/blogs/2010/01/21/smart-tag-single-binding/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Smart tag – базовое применение</title>
		<link>http://software.intel.com/ru-ru/blogs/2010/01/19/smart-tag/</link>
		<comments>http://software.intel.com/ru-ru/blogs/2010/01/19/smart-tag/#comments</comments>
		<pubDate>Tue, 19 Jan 2010 15:00:51 +0000</pubDate>
		<dc:creator>Andrey Gordienkov (Intel)</dc:creator>
				<category><![CDATA[Intel Software Network]]></category>
		<category><![CDATA[Разработка софта]]></category>
		<category><![CDATA[Custom Controls]]></category>

		<guid isPermaLink="false">http://software.intel.com/ru-ru/blogs/2010/01/19/smart-tag/</guid>
		<description><![CDATA[.dp-highlighter {width: 100%!important;} Intro Долгое время я с удовольствием и радостью пользовался смарт тэгами. Вообще-то я долгое время даже не знал, как эта штука правильно называется, но это не мешало с пользой использовать смарт тэги. Некоторое время назад я начал разрабатывать собственные компоненты, но это не сильно сокращало время настройки пользовательского интерфейса. Очень много времени [...]]]></description>
			<content:encoded><![CDATA[<style type="text/css">
.dp-highlighter {width: 100%!important;}
</style>
<h2>Intro</h2>
<p>Долгое время я с удовольствием и радостью пользовался смарт тэгами. Вообще-то я долгое время даже не знал, как эта штука правильно называется, но это не мешало с пользой использовать смарт тэги. Некоторое время назад я начал разрабатывать собственные компоненты, но это не сильно сокращало время настройки пользовательского интерфейса. Очень много времени уходит на то, чтобы найти необходимое свойство в Property view, выставить нужное значение. Это не проблема, если приложение небольшое и надо настроить только пару экранов, но превращается в головную боль, когда у тебя более 30 сложных экранов с самописными компонентами. Вобщем я решил найти, как же делаются смарт тэги (эти маленькие чудесные треугольнички) и настроить их для самописных компонентов и некоторых стандартных.</p>
<p><a href="http://softblog.violet-tape.ru/wp-content/uploads/2010/01/smartTagSimple006.png"><img class="alignnone size-full wp-image-155" src="http://softblog.violet-tape.ru/wp-content/uploads/2010/01/smartTagSimple006.png" alt="" width="528" height="240" /></a></p>
<p>Результаты поиска увенчались успехом и, в результате некоторых тестов и проб пера, получилось то, что я хотел. И это действительно стало экономить кучу времени!</p>
<p>В серии статей про смарт тэги я бы хотел поделиться полученными знаниями и рассказать все с самого начала.</p>
<p><span id="more-2002975"></span></p>
<p>Для всего нижеописанного советую поставить <a href="http://www.jetbrains.net/confluence/display/ReSharper/ReSharper+5.0+Nightly+Builds" target="_blank">ReSharper 5</a>. В скобках горячие клавиши приведены для решарпера.</p>
<h2>Что такое smart tag?</h2>
<p><a href="http://softblog.violet-tape.ru/wp-content/uploads/2010/01/smartTagSimple001.png"><img class="alignnone size-full wp-image-150" src="http://softblog.violet-tape.ru/wp-content/uploads/2010/01/smartTagSimple001.png" alt="" width="416" height="405" /></a></p>
<p>Смарт тэги – элементы пользовательского интерфейса похожие на быстрое меню с наиболее популярными общими действиями. Они доступны в режиме дизайна форм. Большинство стандартных компонентов поставляемых с .Net Framework содержат смарт тэги или списки быстрых действий.</p>
<p>Смарт тэги состоят из трех основных вещей:</p>
<ul>
<li>Действия ­– выглядят как ссылки и по нажатии совершается какое-то заранее определенное действие по форматированию компонента.</li>
<li>Поля редактирования – может быть много различных типов: редактор текста, картинок, дат, биндинг.</li>
<li>Текст – просто текст, который  можно использовать для вывода справочной информации. Не редактируемое поле.</li>
</ul>
<p>Делая изменения в смарт тэге, вы автоматом меняете соответствующее свойство в компоненте.</p>
<h2>Примеры применения и соображения как это можно использовать</h2>
<p>Когда вы создаете свой собственный компонент, вы хотите использоваться его с максимальной возможной простотой в настройке, а ковыряние в окне свойств к этому явно не отнести. К примеру, я создал шаблон для шапки моего приложения и хочу, чтобы он прикреплялся (dock) к верху формы. Мне надо переключиться на экран свойств, найти свойство Dock и выбрать из выпадающего списка Top. Это долго даже если по полной использовать горячие клавиши. Но если сделать смарт тэг, все пройдет в разы быстрее! Мышка уже в районе компонента и очень легко добраться до смарт тэга и нажать на ссылку.</p>
<p>Смарт тэги есть у ComboBox, PictureBox, Panel и у многих других компонентов. Но, к сожалению, для Button или Label и еще некоторых общих компонентов нет смарт тэгов. На мой взгляд это было бы полезно создать смарт тэги для этих компонентов и задавать имена и подписи не переключаясь в окно свойств. А, как идея, хороша? <img src='http://software.intel.com/ru-ru/blogs/wordpress/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>Ко всему прочему, в моем стиле программирования UI широко применение биндинга и я хочу сделать эту операцию быстрой. К примеру, забиндить Action&lt;&gt; к свойству Tag или к какому-нибудь новому свойству.</p>
<h2>Создание своего компонента</h2>
<p>Есть два пути создания своего компонента. Первый – создать новый класс и наследовать его от <em>Component</em>; другой путь создать класс наследник <em>UserControl</em>. Легче всего это создается с помощью контекстного меню студии Add.</p>
<p>Когда мне нужен новый компонент как композиция уже существующих, я использую UserConrol. Это наиболее общий способ создания новых компонентов в процессе написания прикладного ПО. Но если вы желаете подредактировать существующие компоненты, я советую использовать Component.</p>
<p>Создаем новый проект типа DLL Library и называем его в духе “SmartTagTutorial”. После этого должен появится солюшен  (не знаю как это адекватно перевести) с одним проектом. Для задач тестирования неплохо было бы создать и проект типа WinForms.</p>
<p><a href="http://softblog.violet-tape.ru/wp-content/uploads/2010/01/smartTagSimple002.png"><img class="alignnone size-full wp-image-151" src="http://softblog.violet-tape.ru/wp-content/uploads/2010/01/smartTagSimple002.png" alt="" width="224" height="149" /></a></p>
<p>После всех манипуляций должно появится что-то похожее.</p>
<p>Знакомо все пока что выглядит, а? <img src='http://software.intel.com/ru-ru/blogs/wordpress/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>Следующим шагом добавим новый UserControl. Вызываем контекстное меню проекта SmartTagTutorial и выбираем нужный пункт (Add &gt; User Control). Далее может быть самая сложная часть – придумать, что же будет делать новый компонент, и что мы хотим в нем оптимизировать. Я остановился на создании шапки.</p>
<p>Итак, теперь у нас есть класс наследник UserControl. Настало время проявить свою фантазию и нарисовать, как будет выглядеть шапка. У меня получилось как на рисунке ниже.</p>
<p><a href="http://softblog.violet-tape.ru/wp-content/uploads/2010/01/smartTagSimple005.png"><img class="alignnone size-full wp-image-154" src="http://softblog.violet-tape.ru/wp-content/uploads/2010/01/smartTagSimple005.png" alt="" width="560" height="113" /></a></p>
<p>Есть основной текст, дополнительный текст с описанием и заготовка для картинки. Думаю, будет достаточно.  Наступило время писать код, начнем от простого к сложному.</p>
<h2>Создание ссылок действий.</h2>
<p>Действия, в контексте смарт тэгов, это методы без параметров. Визуально они представлены ссылками, и действие выполняется сразу при нажатии. В нашем случае будет логично сделать так, чтобы при нажатии наш компонент прикреплялся к верху родительского контейнера. Все ведь согласны с тем, что каждый раз выискивать Dock и выставлять нужное значение скучно?</p>
<p>Переключаемся в Solution Explorer (<em>ctrl+alt+L</em>), выбираем SmartTagTutorial, создаем новый класс (<em>alt+ins</em>) и называем его MyControlDesiner. Для того чтобы все заработало, наследуем его от класса ControlDesigner.</p>
<pre name="code" class="C#">public class MyControlDesigner : ControlDesigner { ... }</pre>
<p>Теперь необходимо переопределить свойство <strong>Verbs</strong>. Нажимаем в редакторе кода <em>alt+ins</em>, выбираем Override members и выделяем Verbs. Получаем заготовку перегрузки, где надо написать тело метода.</p>
<pre name="code" class="C#">public override DesignerVerbCollection Verbs {
    get { throw new NotImplementedException (); }
}</pre>
<p>Все «действия» являются имплементацией DesignerVerb и содержатся в <strong>DesignerVerbCollection</strong>. Предлагаю создать новый метод, который будет заполнять коллекцию .</p>
<pre name="code" class="C#">private void SetVerb() {
    verbs.Clear();
    if (base.Control.Dock != DockStyle.None) {
        verbs.Add(new DesignerVerb("Undock parent top ", OnVerb));
    }
else {
       verbs.Add(new DesignerVerb("Dock parent top ", OnVerb));
    }
}</pre>
<p>Переменная verbs определена в теле класса как экземпляр DesignerVerbCollection. В приведенном куске кода видно как создаются «действия». Первый параметр это текст который будут видеть конечные пользователи компонента; второй – EventHandler который среагирует на клик. Посмотрим поближе на метод OnVerb.</p>
<pre name="code" class="C#">protected void OnVerb(object sender, EventArgs e) {
    (base.Control).Dock = (base.Control).Dock == DockStyle.None ? DockStyle.Top : DockStyle.None;
}</pre>
<p>В нашем случае он достаточно прост. Но в целом  тут можно писать все что душе угодно связанное с подконтрольным компонентом. Для этого есть ссылка <strong>base.Control</strong>.</p>
<p>Не следует, однако, увлекаться созданием «действий», потому что у смарт тэгов нет механизма скроллинга и все что выйдет за пределы экрана абсолютно недоступно для дальнейшего использования.</p>
<p>Когда  у нас появился класс дизайнер, наступило время показать как он присоеденяется к нужному компоненту. Открываем код для нашего компонента и добавляем следующий код:</p>
<pre name="code" class="C#">[Designer(typeof(MyControlDesigner))]</pre>
<p>Должно получится примерно вот так:</p>
<pre name="code" class="C#">[Designer(typeof(MyControlDesigner))]
public partial class MyControl : UserControl { … }</pre>
<p>Пересобираем приложение и проверяем что получилось. Открываем форму (Form1) из проекта WinForms, выбираем окно инструментов (<em>ctrl+alt+x</em>) и перетаскиваем на компонент на форму. Выделяем компонент и видим знакомый треугольник.</p>
<p><a href="http://softblog.violet-tape.ru/wp-content/uploads/2010/01/smartTagSimple003.png"><img class="alignnone size-full wp-image-152" src="http://softblog.violet-tape.ru/wp-content/uploads/2010/01/smartTagSimple003.png" alt="" width="317" height="132" /></a></p>
<h2>Создание полнофункционального смарт тэга</h2>
<p>О да, это гораздо интереснее и мощнее. Я думаю, что если правильно настроить смарт тэг, то эффективность работы с компонентом вырастет в разы! Особенно на ранних стадиях разработки. Я хочу чтобы компоненты настраивались по принципу «здесь и сейчас», без всего этого скроллинга по окну свойств. Бьюсь об заклад, что переименовать компонент, задать осмысленную подпись и настроить биндинг хочется сразу после создания компонента. Ну так мы это и сделаем!</p>
<p>Перво-наперво, создаем еще один класс и называем его MyControlDesignerEx (Ex значит Extended). Этот класс должен быть пронаследован от <strong>ParentControlDesigner</strong>. Для наших нужд будет достаточно переопределить свойство <strong>ActionList</strong>.</p>
<pre name="code" class="C#">public override DesignerActionListCollection ActionLists { get { … }}</pre>
<p>В этом свойстве будет создан экземпляр класса в котором будет уже настоящая работа. И в качестве базового класса у него будет ControlActionListBase.</p>
<pre name="code" class="C#">public class MyControlActionList : ControlActionListBase { … }</pre>
<p>На данный момент можно уже написать реализацию свойства ActionLists. План работ такой: создать экземпляр DesignerActionListCollection для возврата; создать DesignerActionList, в котором будет хранится только что созданная коллекция.</p>
<p>DesignerActionList принимает в конструктор 2 параметра: сам компонент и его дизайнер. У нас есть все необходимые ингридиенты и можно продолжать. Т.к. у нас дизанер является наследником ParentControlDesigner, то возможно использовние некоторых полезных родительских свойств, например такого как <strong>Control</strong>. Это свойство представляет собой ссылку на экземпяр компонента к которому применен дизайнер. Ладно, на практике все гораздо проще!</p>
<pre class="C#" style="width: 100%;">public override DesignerActionListCollection ActionLists {
    get {
        if (actionLists == null) {
            actionLists = new DesignerActionListCollection();
            actionLists.Add(new MyControlActionList((MyControl) Control, this));
         }
         return actionLists;
    }
}</pre>
<p>Я решил создать actionLists за пределами свойства, чтобы ускорить дальнейшее использование. В большинстве случаев этого кода будет достаточно, потому что смарт тэги как правило, не меняются в ответ на пользовательские действия. В этом куске кода инициализируется класс коллекции и создается список того, что увидит пользователь. Можно сказать, что основное действо будет запрограммировано в классе MyControlActionList.</p>
<p>В классе MyControlActionList  необходимо переопределить метод <strong>GetSortedActionItems</strong> . Сделав это мы определим внешний вид и функционал смарт тэга. В этом методе могут быть объявлены свойства, заголовки, действия которые будут доступны через смарт тэг.</p>
<h2>Типы элементов в смарт тэге.</h2>
<p><a href="http://softblog.violet-tape.ru/wp-content/uploads/2010/01/smartTagSimple004.png"><img class="alignnone size-full wp-image-153" src="http://softblog.violet-tape.ru/wp-content/uploads/2010/01/smartTagSimple004.png" alt="" width="408" height="161" /></a></p>
<p>На рисунке представлены все основные части.</p>
<p><strong>Header</strong> – просто заголовок. Он просто представляет логическую категорию. Нет никаких специальных свойств, просто показывает текст жирным шрифтом и является якорем для группировки элементов. Добавить его очень просто:</p>
<pre name="code" class="C#">items.Add(new DesignerActionHeaderItem("Information"));
items.Add(new DesignerActionHeaderItem("Appearance"));</pre>
<p>где items экземпляр класса DesignerActionItemCollection.</p>
<p>Следующий, простой как лом в разрезе, объект это <strong>Text</strong>. Можно показывать статичный текст с разъяснениями, всякие копилефты и прочее. Создать его тоже легко и незатейливо.</p>
<pre name="code" class="C#">items.Add(new DesignerActionTextItem("some text", "Information"));</pre>
<p>Никаких дополнительных действий не надо. Дешево и сердито.</p>
<p><strong>Method</strong> – выглядит и работает как «быстрые действия». Поскольку MyControlActionList класс предоставляет достаточно богатую функциональность, то и создание этого элемента будет посложнее.</p>
<pre name="code" class="C#">items.Add(new DesignerActionMethodItem(this,
                                      "Dock",
                                      "Dock to parent control",
                                      "Settings",
                                      "Dock top",
                                      true));</pre>
<ul>
<li>Вторым параметром идет имя метода который будет вызван на щелчек мыши;</li>
<li>Третьим – название для пользователя;</li>
<li>Четвертым – категория, в которой отобразить «действие»;</li>
<li>Пятым – всплывающая подсказка;</li>
<li>Последний параметр для того, чтобы указать показывать в окне Свойства или нет.</li>
</ul>
<p>Теперь вы обязанны создать метод с таким же именем (с учетом регистра), которое вы написали во втором параметре. Метод ничего не принимает и не возвращает.</p>
<pre name="code" class="C#">private void Dock() {
    linkedControl.Dock = linkedControl.Dock == DockStyle.None ? DockStyle.Top : DockStyle.None;
}</pre>
<p>Если категория, указанная в четвертом параметре не существует, то метод будет показан после всех категорий.</p>
<p><strong>Property –</strong> последний в списке, но не по значению. Я думаю это вообще главная побудительная причина для написания смарт тэгов. Для создания свойства надо написать следующий код:</p>
<pre name="code" class="C#">items.Add(new DesignerActionPropertyItem(
                    "Caption",
                    "Header Main Caption",
                    "Appearance",
                    "Sets the support header text."));</pre>
<ul>
<li>Первый параметр это точное имя свойства, которое обрабатывает значения, передаваемые в компонент смарт тэга. Свойство объявляется в текущем классе;</li>
<li>Второй ­– текст для пользователя;</li>
<li>Третий – в какую категорию отнести элемент;</li>
<li>Последний – для всплывающей подсказки.</li>
</ul>
<p>НЕ ПЫТАЙТЕСЬ проверить смарт тэг в действии до того, как вы реализуете все свойства и методы объявленные в описанных элементах. Студия просто упадет, если не будет свойства Caption или метода Dock.</p>
<p>В соответсвии со всем вышесказанным, в классе MyControlActionList надо определить свойство Caption.</p>
<pre name="code" class="C#">public string Caption {
    get { return (string)GetPropertyByName("MainText").GetValue(linkedControl); }
    set { GetPropertyByName("MainText").SetValue(linkedControl, value); }
}

internal PropertyDescriptor GetPropertyByName(string propName) {
    var prop = TypeDescriptor.GetProperties(LinkedControl)[propName];
    if (null == prop) {
        throw new ArgumentException("Matching property not found.", propName);
    }
    return prop;
}</pre>
<p>Да, более сложное задание свойств, но это потому что будет генерироваться код в бэкграунде формы. Без этого, например, нельзя будет сменить имя созданного компонента.</p>
<p>Для большинства базовых типов которые используются для свойств, в студии есть базовые графические редакторы значений. Для строки это будет EditBox, для изображений Image Set Dialog, ну и так далее. Но иногда требуется явно задать какой редактор использовать. Предположим, что мы хотим для Caption использовать редактор который позволяет вводить текст в несколько строк. Тогда надо к свойству Caption добавить аттрибут:</p>
<pre name="code" class="C#">[Editor(typeof (MultilineStringEditor), typeof (UITypeEditor))]</pre>
<p>В итоге у меня получился такой вот смарт тэг:</p>
<p><a href="http://softblog.violet-tape.ru/wp-content/uploads/2010/01/smartTagSimple006.png"><img class="alignnone size-full wp-image-155" src="http://softblog.violet-tape.ru/wp-content/uploads/2010/01/smartTagSimple006.png" alt="" width="528" height="240" /></a></p>
<h2>Outro</h2>
<p>Пересоберите солюшен, откройте форму и перенесите новый компонент для того, чтобы увидеть ваш смарт-тег. Попробуйте добавить новые свойства и действия. Поэкспериментируйте с типами свойств, например DateTime, DockStyle.</p>
<p>В следующей статье цикла я расскажу о том, как созадвать методы для биндинга и как дебажить смарт тэги.</p>
<p><a href="http://softblog.violet-tape.net/download/Smart_Tag_-_Simple.zip" target="_blank">Source code</a>.</p>
<p>Hard’n’heavy!</p>
<p>Подпишись на <a href="http://feeds.feedburner.com/VioletTapeRu">RSS</a>!</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/ru-ru/blogs/2010/01/19/smart-tag/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Hello world!</title>
		<link>http://software.intel.com/ru-ru/blogs/2010/01/18/hello-world-2/</link>
		<comments>http://software.intel.com/ru-ru/blogs/2010/01/18/hello-world-2/#comments</comments>
		<pubDate>Mon, 18 Jan 2010 13:19:47 +0000</pubDate>
		<dc:creator>Andrey Gordienkov (Intel)</dc:creator>
				<category><![CDATA[Intel Software Network]]></category>

		<guid isPermaLink="false">http://software.intel.com/ru-ru/blogs/2010/01/18/hello-world-2/</guid>
		<description><![CDATA[Добро пожаловать! В своем блоге я планирую освещать особенности разработки пользовательских приложений на .net. В планах на первое время написать статьи о разработке custom user's control. Какие подводные камни вас могут (и будут) ожидать, как их избежать, что можно улучшать, и т.д. Я разработчик программного обеспечения. Пишу программы на C#, испытываю нездоровую страсть к интерфейсам [...]]]></description>
			<content:encoded><![CDATA[<p>Добро пожаловать!</p>
<p>В своем блоге я планирую освещать особенности разработки пользовательских приложений на .net. В планах на первое время написать статьи о разработке custom user's control. Какие подводные камни вас могут (и будут) ожидать, как их избежать, что можно улучшать, и т.д.</p>
<p>Я разработчик программного обеспечения. Пишу программы на C#, испытываю нездоровую страсть к интерфейсам и созданию новых компонентов, что по сути не является профилем нашей команды в компании. В результате получается, что образуется огромный пласт знаний, который не передается коллегам, чтобы эти знания дальше росли и множились, возвращаясь ко мне. Надеюсь что этот блог позволит мне передать большую часть знаний читателям, которые пригодятся им, а в процессе экспериментов смогут что-то новое сообщить и мне.</p>
<p>Практический опыт использования Domain Driven Design, Test Driven Design, Extreme programming, Agile, SCRUM на протяжении вот уже двух лет. Если про это интересно, то тоже могу рассказать немало.</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/ru-ru/blogs/2010/01/18/hello-world-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

