wpfdrawingvisual

DrawingVisual not showing in WPF Canvas inside a Window


I created a minimal project in order to "get going" with drawing with DrawingVisuals in WPF (being very beginner so far).

My project contains only XAML and code behind for the main window. The only purpose of this project is open a window and display some "signal noise" filling the available space.

MainWindow.xaml is this:

<Window x:Class="MinimalPlotter.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:MinimalPlotter"
        Title="MainWindow" Width="1200" Height="800"
        WindowStartupLocation="CenterScreen">

        <Canvas Height="500" Width="700" x:Name="drawingArea" Margin="50" Background="Gray">
            <local:VisualHost Canvas.Top="0" Canvas.Left="0" x:Name="host" Width="700" Height="500" />
        </Canvas>
</Window>

And code behind is this:

namespace MinimalPlotter
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }

    public class VisualHost : FrameworkElement
    {

        public VisualHost()
        {
            int h = (int)this.Height;
            int w = (int)this.Width;

            Random random = new Random();
            double r;

            DrawingVisual path = new DrawingVisual();

            StreamGeometry g = new StreamGeometry();
            StreamGeometryContext cr = g.Open();
            cr.BeginFigure(new Point(0,0), false, false);
            for (int i = 0; i < w; i++)
            {
                // ugly calculations below to get the signal centered in container
                r = (random.NextDouble()-0.5) * h -h/2;
                cr.LineTo(new Point(i, r), true, false);
            }
            cr.Close();
            g.Freeze();

            DrawingContext crx = path.RenderOpen();
            Pen p = new Pen(Brushes.Black, 2);
            crx.DrawGeometry(null, p, g);

            // Ellipse included for "visual debugging"
            crx.DrawEllipse(Brushes.Red, p, new Point(50,50), 45, 20);

            crx.Close();

            this.AddVisualChild(path);
        }
    }
}

The problem is: when the window opens, the Canvas shows up in the center, as expected (with a gray background), but no signal gets plotted. A previous version of this code worked fine using Path geometry, but with DrawingVisual no geometry is shown (not even the ellipse geometry included for debugging).

Thanks for reading!


Solution

  • Your VisualHost class would also have to override the VisualChildrenCount property and the GetVisualChild method:

    public class VisualHost : FrameworkElement
    {
        private DrawingVisual path = new DrawingVisual();
    
        public VisualHost()
        {
            ...
            AddVisualChild(path);
        }
    
        protected override int VisualChildrenCount
        {
            get { return 1; }
        }
    
        protected override Visual GetVisualChild(int index)
        {
            return path;
        }
    }
    

    Please note also that it is considered good practice to use IDisposable objects like StreamGeometryContext and DrawingContext in using statements:

    var g = new StreamGeometry();
    using (var cr = g.Open())
    {
        cr.BeginFigure(new Point(0,0), false, false);
        ...
        // no need for cr.Close()
    }
    
    using (var crx = path.RenderOpen())
    {
        var p = new Pen(Brushes.Black, 2);
        crx.DrawGeometry(null, p, g);
        crx.DrawEllipse(Brushes.Red, p, new Point(50,50), 45, 20);
        // no need for crx.Close()
    }