2010-08-08 2 views
7

Ho un progetto di Silverlight 3 con qualcosa di simile:MSBuild: come posso creare e utilizzare un'attività per convertire gli elementi di contenuto al momento della compilazione?

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

Fondamentalmente ho aggiunto un file PNG al mio progetto e impostare la sua azione build per "Contenuto". Funziona bene

Ora quello che mi piacerebbe fare è essere in grado di aggiungere le immagini in un formato diverso al mio progetto, e li hanno convertiti in PNG al momento della compilazione - in modo che il risultato finale è come se avessi ha aggiunto un'immagine PNG al progetto (come Contenuto) in primo luogo.

In altre parole, voglio che l'immagine appaia, in formato PNG, nel mio pacchetto XAP.

Idealmente mi piacerebbe farlo in modo che funzioni con Visual Web Developer 2008 Express (quindi posso aggiungere file di immagine al mio progetto trascinandoli nell'IDE e magari modificando la loro azione di compilazione), e senza apportare modifiche a livello di sistema.

Il formato specifico che voglio convertire è XCF - Ho già il codice .NET per fare la conversione in PNG. Presumo che devo create a MSBuild Task.

Non ho molta esperienza MSBuild e mi piacerebbe sapere come mettere insieme una cosa del genere.


Sulla base della mia comprensione di massima di come funziona MSBuild, penso che ho bisogno di sapere:

  • Come creare una collezione di articoli da (ri) spostandoli dalla @(Content) (o qualche altro), in base alla loro estensione di file?
    • OR: creare un'azione di generazione personalizzata che posso utilizzare in Visual Web Developer 2008 Express
  • Come per ricevere il percorso di elementi di input in un Task?
  • Dove (.NET o MSBuild?) E Come specificare la posizione dei file di output generati da un Task?
  • Come assicurarsi che un file venga ricostruito se il suo file di input cambia?
  • Dove (probabilmente BeforeBuild?) E Come reinserire gli articoli convertiti in @(Content)? (O dovrei usare qualche altra collezione?)
    • OPPURE: Qualche altro modo di inserirli nell'XAP?

E se questo sembra un modo ragionevole per fare le cose o se ho perso qualcosa?

+1

Ho scoperto che 'AvailableItemName' farà apparire un'azione di compilazione personalizzata in VWD. Riferimento: http://msdn.microsoft.com/en-us/library/ms171468(VS.80).aspx –

risposta

13

Hai chiesto specifiche sotto-domande al fine di raggiungere il vostro obiettivo nel complesso, si presume vuoi conoscere MSBuild, piuttosto che ottenere una risposta automatica al tuo compito generale (che è quello che otterrai da molte altre persone a causa della tua generosità), quindi risponderò alle tue domande individuali e poi cercherò di farle andare tutte in una soluzione.

Quindi supponiamo di voler convertire tutti i file .jpg in .png.

Creare una sotto-lista dall'elenco degli elementi contenuti in base all'estensione:

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

Ricevi il percorso della voce in un compito.

Due modi: dipende dall'input che l'attività può accettare. In questo modo è come un "foreach" su ogni elemento in sottolista, e tenderebbe ad usarlo con un compito Exec:

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

Specifica di un percorso di uscita dipende anche dalla .exe o l'operazione che si sono e che cosa significa un percorso di output per un particolare compito:

è una directory, o solo un nome di file con un'estensione diversa. Ma darò per scontato che si desidera i file di output con lo stesso nome, ma un diverso estensione:

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

Come ricostruire il png se (viene pulito o) le modifiche jpg.

Bene, questo sta utilizzando l'attributo Ingressi e uscite dell'elemento di destinazione contenente in cui viene eseguito il comando di conversione. Gli input specificano quali sono i file di origine e gli output specificano ciò che il target produrrà.MSBuild poi confronta l'datetime degli ingressi con il datetime dell'uscita e se non sono aggiornate, quindi le uscite ottenere ricostruito

<Target Name="ConvertJpg" 
     Inputs="@(Content)" 
     Outputs="@(Content -> '%(RootDir)%(Directory)%(Filename).png')" 
     Condition=" '%(Extension)' == '.jpg' " 
  • Ingressi dice che vogliamo usare il "Contenuto" ItemGroup
  • L'attributo Condition garantisce che stiamo lavorando solo con gli elementi Content che terminano con l'estensione .jpg
  • L'attributo Output dice che degli input con cui stiamo lavorando genereremo file con percorso e nome file simili, ma terminare con l'estensione .png

Infine, hai individuato correttamente la necessità di reiniettare nuovamente i file .png generati nel gruppo di elementi @Content - beh, è ​​facile, basta includerli nell'elemento Contenuto. Ricorda che la sottolista contiene file .jpg - vogliamo quei file ma con un finale .png. Anche noi non vogliamo che i file .jpg del gruppo di articoli contenuti una volta png è stata generata

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

Quindi riassumendo, il vostro obiettivo sarebbe simile a questa credo:

<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> 

A modo, ImageMagik ha uno strumento da riga di comando che convertirà jpg in png ...

+0

Ottima risposta. Ho una piccola domanda di follow-up: se volessi che l'output diventi temporaneo (come la directory obj), sarebbe appropriato: '$ (IntermediateOutputPath)% (Identity) \% (Filename) .png'? –

+0

Un'altra domanda sulla tua risposta: le immagini jpg sono state rimosse da '@ (Contenuto)' dopo l'esecuzione del target 'ConvertJpg'? Avrei dovuto indovinare (cosa che li avrebbe messi nell'output, il che è male) - anche se sembra che l'uso di un Item Name/Build Action specifico per jpg risolvesse facilmente questo, se si tratta di un problema. –

+0

Non utilizzare% (Identity) come questo, che contiene i valori che sono stati digitati nell'attributo "Include". Presumo che tu voglia il nome della cartella in questo modo: $ (IntermediateOutputPath) \% (Directory) \% (FileName) .png Ho modificato la mia risposta per rispondere alla tua altra preoccupazione (IE rimuove jpg dal contenuto) –

0

Invece di creare un'attività di MSBuild è anche possibile creare uno strumento personalizzato e specificarlo nello Strumento personalizzato nelle proprietà del file immagine.

"uno strumento personalizzato trasformerà un file in fase di progettazione e porrà l'output della trasformazione in un altro file"

esempioDataSet. ha il proprio strumento di trasformazione attraverso il quale otteniamo una classe da utilizzare nella nostra applicazione.

il vantaggio di questo approccio è che si possibile utilizzare il file generato in fase di progettazione tempo pure.

come esempio di implementazione può essere trovato alla http://www.drewnoakes.com/snippets/WritingACustomCodeGeneratorToolForVisualStudio/

+0

Questo sembra richiedere la modifica del registro sulla macchina utilizzando lo strumento? –

+0

sì per registrare il tuo strumento come un generatore di codice. è possibile distribuirlo come programma di installazione o file .reg per eseguire le voci del registro. –

2

Credo che si desidera qualcosa di simile:

<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> 

in cui si specifica una nuova JPGContent BuildAction che converte.

(forse vedere anche http://msdn.microsoft.com/en-us/library/ms164313.aspx e notare che %22 è solo un modo per incorporare una virgoletta in un attributo.)