Archive for April, 2010

C# .Net – Render XAML to Image

April 26, 2010

I’ve been trying to find a way to render XAML to PDF or SVG but I’ve had no luck in finding code examples on how to do this. So, for the moment I’ve resorted to rendering XAML to an Image.

Here are the code snippets that I came up with do the job. This code requires .Net Framework 3.5 or later.

Please leave comments if you know how to get from XAML to PDF via an API. I would be really grateful.

public static Stream XamlToImageSteam(
    XmlTextReader xmlReader, BitmapEncoder encoder, Stream outputStream,
    double dpiX, double dpiY ) {

    Window wind = new Window();
    wind.WindowStyle = WindowStyle.None;
    wind.ShowInTaskbar = false;
    wind.ShowActivated = false;

    // Create Minimized so the window does not show. wind.WindowState = System.Windows.WindowState.Minimized;
    wind.SizeToContent = SizeToContent.WidthAndHeight;

    wind.Content = (UIElement)XamlReader.Load(xmlReader);
    wind.Show(); // The window needs to be created for the XAML elements to be rendered. BitmapSource bitmapSrc = visualToBitmap(wind, dpiX, dpiY);

    encoder.Frames.Clear();
    encoder.Frames.Add(BitmapFrame.Create(bitmapSrc));
    encoder.Save(outputStream);

    outputStream.Flush();

    wind.Hide();
    return outputStream;
}
static BitmapSource visualToBitmap( Visual target, double dpiX, double dpiY ) {
    if (target == null) return null;

    Rect bounds = VisualTreeHelper.GetDescendantBounds(target);

    int width = (int)(bounds.Width * dpiX / 96.0);
    int height = (int)(bounds.Height * dpiX / 96.0);

    RenderTargetBitmap renderer = new RenderTargetBitmap(
            width, height, dpiX,
            dpiY, PixelFormats.Pbgra32);

    renderer.Render(target);

    return renderer;
}

Here is an example of rendering some XAML to a png image:-

double dpiX = 96.0;
double dpiY = 96.0;

string xaml =
    "<Page\r\n" +
    " xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\r\n" +
    " xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\">\r\n" +
    " <Canvas>\r\n" +
    " <Rectangle Width=\"220\" Height=\"100\"\r\n" +
    " RadiusX=\"10\" RadiusY=\"10\" Fill=\"#90d0ff\"/>\r\n" +
    " <TextBlock Canvas.Left=\"25\" Canvas.Top=\"25\"\r\n" +
    " FontSize=\"16\" Foreground=\"White\">Mike Coxeter's .Net Blog</TextBlock>\r\n" +
    " <TextBlock Opacity=\".5\" Canvas.Left=\"26\" Canvas.Top=\"50\"\r\n" +
    " FontSize=\"16\" Foreground=\"White\" >C#, .Net, WPF</TextBlock>\r\n" +
    " </Canvas>\r\n" +
    "</Page>";

XmlTextReader xmlReader = new XmlTextReader(new StringReader(xaml));
using (Stream imageStream = File.Create(@"c:\dotNetBlog.png")) {
    XamlToImageSteam(xmlReader, new PngBitmapEncoder(), imageStream, dpiX, dpiY);
}

dotNetBlog Image produced from above Example

Lists that notify when items are added & removed

April 11, 2010

I often find myself wishing that collections such as List<T> could issue notifications when changes are made to the collection.

This could be particularly useful when you expose a collection as a property from a class. It is often desirable to perform some action on the class if the client changes the collection.

Averager averager = new Averager();
IList<double> numbers = averager.Numbers;

numbers.Add(10);
numbers.Add(5);

Assert.IsTrue(averager.Average == 7.5);

numbers.Add(32);

Assert.IsTrue(averager.Average == 15.666666666666666);

In the code above you can see that Averager passes out a standard list. We can modify the list externally and yet the averager object is kept up to date.

public class Averager {
    public Averager() {
        numbers = new ListNotifyChanged<double>();
        numbers.Changed += numbers_Changed;
    }

    public double Average { get; private set; }

    ListNotifyChanged<double> numbers = null;
    public IList<double> Numbers { get { return numbers; } }

    void numbers_Changed( object sender, ListNotifyChanged<double>.ChangedEventArgs e ) {
        Average = numbers.Average();
    }
}

The ListNofityChanged<T> class is a collection class that closely resembles the List<T> class. However, it fires change notifications events when items are added or removed from the list.

Here is the full implementation of ListNofityChanged<T>

/// <summary>
/// A generic list that will notify when there are
/// changes made to the list.
/// </summary>
public class ListNotifyChanged<T> : IList<T> {
    IList<T> list = new List<T>();

    public ListNotifyChanged() { }

    public ListNotifyChanged( int capacity ) {
        list = new List<T>(capacity);
    }

    public ListNotifyChanged( IList<T> list ) {
        this.list = list;
    }

    public ListNotifyChanged( IEnumerable<T> collection ) {
        list = new List<T>(collection);
    }

    public event EventHandler<ListChangedEventArgs> Changed;
    public event EventHandler<EventArgs> Cleared;

    protected virtual void OnChanged( ListChangedEventArgs e ) {
        if (Changed != null) Changed(this, e);
    }

    protected virtual void OnCleared() {
        if (Cleared != null) Cleared(this, new EventArgs());
    }

    #region IList<T> Members

    public T this[int index] {
        get { return list[index]; }
        set {
            list[index] = value;
            OnChanged(new ListChangedEventArgs(index, value));
        }
    }

    public int IndexOf( T item ) {
        return list.IndexOf(item);
    }

    public void Insert( int index, T item ) {
        list.Insert(index, item);
        OnChanged(new ListChangedEventArgs(index, item));
    }

    public void RemoveAt( int index ) {
        T item = list[index];
        list.Remove(item);
        OnChanged(new ListChangedEventArgs(index, item));
    }

    #endregion

    #region ICollection<T> Members
    public void Add( T item ) {
        list.Add(item);
        OnChanged(new ListChangedEventArgs(list.IndexOf(item), item));
    }

    public void Clear() {
        list.Clear();
        OnCleared();
    }

    public bool Contains( T item ) {
        return list.Contains(item);
    }

    public void CopyTo( T[] array, int arrayIndex ) {
        list.CopyTo(array, arrayIndex);
    }

    public int Count {
        get { return list.Count; }
    }

    public bool IsReadOnly {
        get { return list.IsReadOnly; }
    }

    public bool Remove( T item ) {
        int index = list.IndexOf(item);
        if (list.Remove(item)) {
            OnChanged(new ListChangedEventArgs(index, item));
            return true;
        }
        else
            return false;
    }
    #endregion

    #region IEnumerable<T> Members

    public IEnumerator<T> GetEnumerator() {
        return list.GetEnumerator();
    }

    #endregion

    #region IEnumerable Members

    IEnumerator IEnumerable.GetEnumerator() {
        return ((IEnumerable)list).GetEnumerator();
    }

    #endregion

    public class ListChangedEventArgs : EventArgs {
        public int index;
        public T item;
        public ListChangedEventArgs( int index, T item ) {
            this.index = index;
            this.item = item;
        }
    }
}