2010-08-08 4 views
7

У меня есть 3 проекта Silverlight с чем-то вроде этого:MSBuild: Как создать и использовать задачу для преобразования элементов контента во время сборки?

<ItemGroup> 
    <Content Include="Content\image1.png"> 
    </Content> 
</ItemGroup> 

В основном я добавил файл PNG в мой проект и установить его действие сборки для «Content». Это хорошо работает.

Теперь то, что я хотел бы сделать, это иметь возможность добавлять изображения в другом формате для моего проекта, и они преобразуются в PNG во время сборки - так что конечный результат, как если бы я был добавили PNG-изображение в проект (как Content) в первую очередь.

Другими словами - я хочу, чтобы изображение отображалось в формате PNG в моем пакете XAP.

В идеале я хотел бы сделать это так, чтобы он работал с Visual Web Developer 2008 Express (поэтому я могу добавлять файлы изображений в свой проект, перетаскивая их в IDE и, возможно, меняя их действие сборки) и без каких-либо общесистемных изменений.

Конкретный формат, который я хочу преобразовать, это XCF. У меня уже есть код .NET для преобразования в PNG. Я предполагаю, что должен create a MSBuild Task.

У меня действительно не так много опыта работы с MSBuild, и я хотел бы знать, как свести это вместе.


Основываясь на моем грубом понимании того, как работает MSBuild, я думаю, что мне нужно знать:

  • Как создать коллекцию элементов по (ре), перемещая их из @(Content) (или другая) коллекция, основанная на их расширении файла?
    • ИЛИ: Создание пользовательского Build Action можно использовать в Visual Web Developer 2008 Express
  • Как Получать путь входных элементов в Task?
  • Где (.NET или MSBuild?) И Как указать расположение выходных файлов, сгенерированных Task?
  • Как обеспечить восстановление файла при изменении его входного файла?
  • Где (возможно, BeforeBuild?) И как перевести конвертированные товары в @(Content)? (Или я должен использовать какую-то другую коллекцию?)
    • ИЛИ: Какой-то другой способ получить их в XAP?

И если это кажется разумным способом, чтобы делать вещи, или если я пропустил что-нибудь?

+1

Я обнаружил, что 'AvailableItemName' создаст пользовательское действие сборки в VWD. Ссылка: http://msdn.microsoft.com/en-us/library/ms171468(VS.80).aspx –

ответ

13

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

Итак, скажем, вы хотите преобразовать все файлы .jpg в .png.

Создание вложенного списка из списка элементов контента на основе расширения:

<ItemGroup> 
    <Sublist Include="@(Content)" Condition=" '%(Extension)' == '.jpg' " /> 
</ItemGroup> 

Получить путь элемента в задаче.

Два способа - зависит от ввода, который может принять ваша задача. Таким образом, как «Еогеасп» по каждому пункту в Подсписок, и я, как правило, использовать его с Exec задачи:

<Exec Command="convert.exe /Input:%(Sublist.FullPath)" /> 

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

это каталог или просто имя файла с другим расширением. Но я предполагаю, что вы хотите выводить файлы с тем же именем, но другое расширение:

<Exec Command="convert.exe &quot;%(Sublist.FullPath)&quot; &quot;%(Sublist.RootDir)%(Sublist.Directory)%(Sublist.Filename).png&quot;" />  

Как восстановить PNG, если изменения JPG (или очищается).

Ну, это использует атрибут Inputs and Outputs содержащего целевого элемента, в котором выполняется наша команда convert. Входы указывают, что представляют собой исходные файлы, а выходы указывают, что будет производить цель.MSBuild сравнивает DateTime входов с DateTime выхода, и если они устарели, то выходы получить перестроен

<Target Name="ConvertJpg" 
     Inputs="@(Content)" 
     Outputs="@(Content -> '%(RootDir)%(Directory)%(Filename).png')" 
     Condition=" '%(Extension)' == '.jpg' " 
  • Входы говорит, что мы хотим использовать «Content» ItemGroup
  • Атрибут Condition гарантирует, что мы работаем только с элементами контента, которые заканчиваются расширением .jpg.
  • . .
  • . Атрибут Outputs говорит о том, что из входов, с которыми мы работаем, мы будем генерировать файлы с похожими путями и именами файлов, но заканчивается расширением .png

Наконец, вы правильно заметили, что вам нужно повторно вставить сгенерированные .png-файлы обратно в группу элементов @Content - ну, это просто, просто включите их в элемент «Содержимое». Напомним, что Sublist содержит .jpg файлы - мы хотим эти файлы, но с завершением .png. Мы также не хотим файлы .jpg в группе элемента контента раз в PNG сгенерирован

<Content Remove="@(Sublist)" /> 
<Content Include="@(Sublist -> '%(RootDir)%(Directory)%(Filename).png')" /> 

Итак подводя итог, ваша цель будет выглядеть примерно так я верю:

<Target Name="ConvertJpg" 
     Inputs="@(Content)" 
     Outputs="@(Content -> '%(RootDir)%(Directory)%(Filename).png')" 
     Condition=" '%(Extension)' == '.jpg' " 
    <ItemGroup> 
     <Sublist Include="@(Content)" Condition=" '%(Extension)' == '.jpg' " /> 
    </ItemGroup> 

    <Exec Command="convert.exe /Input:%(Sublist.FullPath) Output=%(Sublist.RootDir)%(Sublist.Directory)%(Sublist.Filename).png" /> 

    <Content Remove="@(Sublist)" /> 
    <Content Include="@(Sublist -> '%(RootDir)%(Directory)%(Filename).png')" /> 
</Target> 

К way, ImageMagik имеет инструмент командной строки, который преобразует jpg в png ...

+0

Отличный ответ. У меня есть небольшой вопрос о последующих действиях. Если бы я хотел, чтобы выход был куда-то временным (например, каталог obj), это было бы уместно: '$ (IntermediateOutputPath)% (Identity) \% (Filename) .png'? –

+0

Еще один вопрос о вашем ответе: удалены ли jpg-изображения из '@ (Content)' после запуска цели ConvertJpg? Я бы не догадался (что бы помещать их в результат, что плохо) - хотя кажется, что использование jpg-специфического Item Name/Build Action легко разрешит это, если это проблема. –

+0

Не используйте% (Identity), подобный этому, - который содержит значения, которые были введены в атрибуте «Включить». Я предполагаю, что вы хотите, чтобы имя папки было таким: $ (IntermediateOutputPath) \% (Directory) \% (имя_файла) .png Я отредактировал свой ответ, чтобы решить вашу другую проблему (IE удаляет jpg из Контента) –

0

Вместо создания задачи MSBuild вы также можете создать инструмент Custom и указать его в Custom Tool в свойствах вашего файла изображения.

«пользовательский инструмент преобразует файл во время разработки и поместит выход преобразования в другой файл»

напримерDataSet. он имеет свой собственный инструмент трансформации, через который мы получаем класс для использования в нашем приложении.

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

в качестве примера реализации можно найти на http://www.drewnoakes.com/snippets/WritingACustomCodeGeneratorToolForVisualStudio/

+0

Возможно, это требует изменения реестра на компьютере с помощью этого инструмента? –

+0

Да, чтобы зарегистрировать ваш инструмент в качестве генератора кода. вы можете распространять его как установщик или .reg-файл для записи реестра. –

2

Я считаю, что вы хотите что-то вроде этого:

<ItemGroup> 
    <JPGContent Include="foo.jpg" /> 
</ItemGroup> 
<Target Name="BeforeBuild" 
     Inputs="@(JPGContent)" Outputs="%(JPGContent.Filename).png"> 
    <!-- replace this with call to jpg->png converter --> 
    <Exec Command="copy %22%(JPGContent.FullPath)%22 %(JPGContent.Filename).png" /> 
    <ItemGroup> 
    <Content Include="%(JPGContent.Filename).png" /> 
    </ItemGroup> 
</Target> 
<Target Name="AfterBuild"> 
    <!-- just demoing that 'Content' now has right value --> 
    <Warning Text ="[email protected](Content)" /> 
</Target> 

, где указан новый JPGContent BuildAction, что он преобразует.

(возможно видеть также http://msdn.microsoft.com/en-us/library/ms164313.aspx и обратите внимание, что %22 это просто способ встроить кавычку в атрибуте.)