Click here to Skip to main content
15,889,862 members
Please Sign up or sign in to vote.
4.00/5 (1 vote)
Goal:
1. Create Canvas.
2. Create MyImage : Image.
3. Draw MyImage by OnRender.
4. Set MyImage source to ImageBrush source.
5. Set ImageBrush to Canvas.Background.

Problem: The canvas gets drawn empty instead of what OnRender should draw.
Question: How to make it draw what is set to draw inside OnRender?
Notes:
1. It draws into Brush, if to add an image via a link.
2. It draws on Canvas, but not into Brush, if to add MyImage as child to Canvas.Children. You can do it by turning a comment off in the code.

Code 1 (using OnRender):
C#
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        Canvas canvas = new Canvas();
        this.Content = canvas;
        canvas.Background = Brushes.Black;

        MyImage myimage = new MyImage();
        myimage.InvalidateVisual();

        ImageBrush brush = new ImageBrush();
        brush.ImageSource = myimage.Source;
        canvas.Background = brush;

        //canvas.Children.Add(myimage); // Draws
    }
}

class MyImage : Image
{
    protected override void OnRender(DrawingContext dc)
    {
        base.OnRender(dc);

        dc.DrawRectangle(Brushes.Red, null, new Rect(0, 0, 100, 100));
    }
}


The second option results the same.
Code 2 (using DrawingVisual):
C#
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        Canvas canvas = new Canvas();
        this.Content = canvas;
        canvas.Background = Brushes.Black;

        MyImage myimage = new MyImage();
        myimage.InvalidateVisual();

        ImageBrush brush = new ImageBrush();
        brush.ImageSource = myimage.Source;
        canvas.Background = brush;

        //canvas.Children.Add(myimage); // Draws
    }
}

class MyImage : Image
{
    public MyImage()
    {
        visuals = new VisualCollection(this);
        visual = new DrawingVisual();
        visuals.Add(visual);

        Draw();
    }

    private void Draw()
    {
        using (DrawingContext dc = visual.RenderOpen())
            dc.DrawRectangle(Brushes.Red, null, new Rect(0, 0, 100, 100));
    }

    VisualCollection visuals;
    DrawingVisual visual;

    protected override Visual GetVisualChild(int index)
    {
        return visuals[index];
    }
    protected override int VisualChildrenCount
    {
        get { return visuals.Count; }
    }
}
Posted
Updated 26-Oct-15 7:47am
v9

1 solution

1. OnRender doesn't render in the code 1 because the visual MyImage is not added into a visual tree. But it renders when you add it into the visual tree of Canvas.
Source:
WPF: InvalidateVisual doesn't draw by OnRender.[^]

2. Even if it renders on the surface of Canvas, it will not render into ImageBrush because the brush is for raster based images, but not for vector based images. That is why it renders a raster image when you add it via a link.

3. You should use VisualBrush[^] as it is for vector based images.

4. VisualCollection/DrawingVisual in the code 2 renders even if you don't add MyImage into the visual tree of Canvas.

Code:
C#
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        Canvas canvas = new Canvas();
        this.Content = canvas;
        canvas.Background = Brushes.Black;

        MyImage myimage = new MyImage();

        VisualBrush visualbrush = new VisualBrush();
        visualbrush.Visual = myimage;
        canvas.Background = visualbrush;
    }
}

class MyImage : Image
{
    public MyImage()
    {
        visuals = new VisualCollection(this);
        visual = new DrawingVisual();
        visuals.Add(visual);

        Draw();
    }

    private void Draw()
    {
        using (DrawingContext dc = visual.RenderOpen())
            dc.DrawRectangle(Brushes.Red, null, new Rect(0, 0, 100, 100));
    }

    VisualCollection visuals;
    DrawingVisual visual;

    protected override Visual GetVisualChild(int index)
    {
        return visuals[index];
    }
    protected override int VisualChildrenCount
    {
        get { return visuals.Count; }
    }
}
 
Share this answer
 
v3

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900