Qualche tempo fa, io e il mio collega Fabio, abbiamo avuto l’idea di generare immagini renderizzando contenuto XAML ed utilizzare queste immagini all’interno di applicazioni web. Da questa idea è nata una libreria costituita da un “motore” che renderizza il contenuto di un FrameworkElement generando un’immagine ed un HttpHandler, attraverso il quale utilizzare questo motore all’interno di applicazione ASP.NET.
La generazione dell’immagine a partire dal FrameworkElement viene eseguita dal metodo RenderToTargetBitmap della classe XamlRender contenuta nella libreria e avviene in questo modo:
- viene forzato il calcolo del layout dell’elemento attraverso i metodi Measure(), Arrange() e UpdateLayout():
element.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
element.Arrange(new Rect(element.DesiredSize));
element.UpdateLayout();
- attraverso un oggetto DrawingVisual, viene disegnato un rettangolo riempito con un VisualBrush ottenuto dal FrameworkElement (per default la dimensione del rettangolo è quella dell’elemento stesso ma è possibile passare la dimensione e il tipo di stretch attraverso i parametri “size” e “stretchMode”):
DrawingVisual dvisual = new DrawingVisual();
using (DrawingContext context = dvisual.RenderOpen())
{
VisualBrush brush = new VisualBrush(element);
brush.Stretch = (size.HasValue && stretchMode.HasValue) ? stretchMode.Value : Stretch.Uniform;
context.DrawRectangle(brush, null, new Rect(new Point(), (size.HasValue) ? size.Value : element.RenderSize));
}
- l’oggetto DrawingVisual creato viene renderizzato su un RenderTargetBitmap:
RenderTargetBitmap renderBitmap = new RenderTargetBitmap(
(size.HasValue) ? (int)size.Value.Width : (int)element.RenderSize.Width,
(size.HasValue) ? (int)size.Value.Height : (int)element.RenderSize.Height,
dpiX,
dpiY,
pixelFormat);
renderBitmap.Render(dvisual);
- viene generato un MemoryStream dell’immagine codificando l’oggetto RenderTargetBitmap (gli encoding possibili sono Gif, Png, Jpeg, Bitmap, Tiff e Wmp):
BitmapEncoder encoder = JpegBitmapEncoder(); // sample with Jpeg encoder
encoder.Frames.Add(BitmapFrame.Create(bitmap));
Stream stream = new MemoryStream();
encoder.Save(stream);
Il metodo RenderToTargetBitmap ha diversi overloads che permettono di specificare vari parametri. Uno di questi è il parametro “bindingParameters”, un dictionary che viene assegnato al DataContext del FrameworkElement che si vuole renderizzare e permette di passare dei parametri allo XAML stesso. Ad esempio è possibile avere uno XAML di questo tipo:
<Border xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
BorderBrush="{Binding Path=.[BorderBrush]}"
BorderThickness="{Binding Path=.[BorderThickness]}"
CornerRadius="{Binding Path=.[CornerRadius]}">
</Border>
La sintassi {Binding Path=.[chiave]} ci permette di bindare degli elementi di un dictionary alle proprietà degli elementi WPF. Il dictionary in questo caso potrebbe essere il seguente:
Dictionary<String, String> bindingParameters = new Dictionary<string, string>();
bindingParameters.Add("BorderBrush", "Red");
bindingParameters.Add("BorderThickness", "4");
bindingParameters.Add("CornerRadius", "10");
Nella sezione downloads è possibile scaricare questa libreria ed un’applicazione WPF di demo che utilizza un file XAML per generare immagini come queste:
Per vedere come utilizzare questa libreria all’interno di un’applicazione ASP.NET leggete il post di Fabio a questo indirizzo:
http://www.fabiofranzini.com/post/2009/03/27/WPF-al-servizio-del-Web.aspx
Currently rated 1.5 by 278 people
- Currently 1.482011/5 Stars.
- 1
- 2
- 3
- 4
- 5
WPF
xaml, rendering, bitmap