L'agosto appena passato l'ho trascorso un po' tra feste sulle spiagge del Garda e un po' ovviamente con il mio caro WPF. In particolare, ho voluto capire per bene, in mancanza di una documentazione, come funziona il formato BAML. Certo penserete: ma non era meglio che te ne stessi in spiaggia un po' di più? In effetti...
Comunque per chi non lo sapesse BAML sta per Binary Application Markup Language ed è il risultato della compilazione del codice XAML. Sebbene nelle prima beta di WPF la compilazione del markup generava il codice per istanziare gli oggetti e valorizzare le proprietà (alla ASP.NET per intenderci), i programmatori MS hanno cambiato strada producendo il BAML. E' un stream di bytes che viene inserito come risorsa all'interno dell'assembly prodotto per poi essere successivamente caricato, dal codice autoprodotto dalla classe che fa da codebehind, tramite il metodo Application.LoadComponent.
Questa scelta permette di sfruttare gli assembly satellite per nazionalizzare in modo automatico il markup XAML o di caricarlo a runtime a seconda del tema.
Per rendere il più veloce possibile il caricamento dei file BAML, il markup viene elaborato subendo una specie di normalizzazione. Il formato è costituito da una serie di record contenenti sempre un byte identificante il tipo di record seguito da una serie di informazioni relative al tipo di record.
I primi record che si incontrano preparano la lettura dello stream. La compilazione infatti comporta l'indicizzazione degli assembly, delle stringhe, dei tipi, delle risorse e delle proprietà. Ogni riferimento è ottenuto quindi tramite intero. Se l'intero è positivo, la voce è da cercare fra quelle elencateci ad inizio file, altrimenti l'indice è da ricercare in alcune voci predefinite. In pratica i tipi e le proprietà più comuni sono indicizzate in WPF in modo fisso e questo comporta un alleggerimento del file e una maggiore velocità di lettura.
In seguito ci viene elencato la lista dei mapping namespace XML/namespace CLR, informazione che in realtà non serve per la lettura, ma più per ricostruire il markup.
Terminata questa preparazione inizia la lettura vera e propria del markup. BAML mantiene sempre una struttura XML Infoset formata da elementi/attributi perciò ad ogni record di tipo ElementStart coincide uno di ElementEnd e così via. Gli elementi sono come sappiamo le classi, mentre gli attributi le proprietà. E' nelle proprietà che c'è il lavoro maggiore. Queste vengono infatte preparate in fase di compilazione in modo da poter, anche in queste caso, essere valorizzare nella maniera più veloce e ottimizzata. Si distinguono in:
- PropertyWithConverter: proprietà che usano il TypeConverter associato alla proprietà o al tipo esposto dalla proprietà;
- PropertyWithExtension: proprietà che usano le MarkupExtension come Static, StaticResource e DynamicResource;
- PropertyTypeReference: proprietà valorizzare con un Type;
- PropertyList: rappresenta una collezione da popolare con gli elementi figli;
- PropertyDictionary: rappresenta la proprietà Resources e verrà quindi seguita da una lista di risorse con chiavi;
- PropertyComplex: sono proprietà complesse, valorizzate a loro volta con altri oggetti.
- PropertyCustom: sono proprietà che prevedono specifici tipi di oggetti come Brush, collezioni di numeri, di punti 2D o 3D.
Tralasciando alcuni dettagli sull'uso delle chiavi che ho fatto fatica a capire come funziona, ma non ho ancora compreso il senso, direi che è tutto qua :-)
Per l'occasione ho creato una libreria con una classe XmlBamlReader: un'implementazione di XmlReader che legge da file BAML e restituisce un XML infoset da caricare con i normali strumenti XML di .NET (XmlDocument, XPathDocument, LINQ for XML, ecc..). La classe decompila correttamente i temi di WPF del .NET Framework 3.0, quindi posso ritenermi più che soddisfatto; certo non è stato semplicissimo.
Attualmente sto applicando la libreria ad un mio applicativo che dovrebbe (se non lo abbandono) permettere di decompilare codice XAML da exe, dll, xbap o applicativi distribuiti con ClickOnce. Vi terrò aggiornati ;-)
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
- Visual Studio 11 beta: le novità di WPF 4.5, l'1 marzo 2012 alle 19:32
- Spettro audio con WPF, il 28 novembre 2007 alle 23:24
- Controllo WPF: AdvancedListBox, il 24 ottobre 2007 alle 19:24
- Multithreading WPF nel Binding, il 21 ottobre 2007 alle 23:40
- WPF attached properties + extension methods, il 10 giugno 2007 alle 22:12