Question

I am trying to create my own graph user control, I have one already working on win forms and I am trying to move it into WPF world.

I am starting with learning how to do drawing, so first thing I was trying to draw a black ellipse that fills an entire window, just to learn how coordinates works in WPF.

So here is the code, when I run the application, nothing is displayed, any idea what am I missing?

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

    protected override void OnRender(DrawingContext drawingContext)
    {
        base.OnRender(drawingContext);

        drawingContext.DrawEllipse(Brushes.Black, new Pen(Brushes.Black, 1), new Point(Width / 2, Height / 2), Width / 2, Height / 2);
    }
}
Was it helpful?

Solution

WPF is very different from WinForms. You do not have something like a Paint event handler where you constantly need to repaint invalidated areas.

The easist way to draw an ellipse that fills the whole window area in WPF is this XAML:

<Window ...>
    <Grid>
        <Ellipse Stroke="Black" Fill="Black"/>
    </Grid>
</Window>

but of course there are a lot of other ways to achieve the same result.

If you need to do more complex things, WPF offers a large variety of classes that support graphics and multimedia. I'd suggest starting to read the Graphics section of the online documentation on MSDN.


To come back to your specific problem, there are several things to mention.

First, you would have seen the result of your OnRender override if you had set the Window's Background property to Transparent and had drawn the ellipse in a color other than Black.

Then you would have realized that the drawn ellipse is larger than the window's client area. This is because the values of the Width and Height properties include the Window border. Even then, using the Width and Height properties for getting the actual width and height of a UI element in WPF is not the proper way, because these properties return double.NaN unless they were explicitly set (except in the Window class).

Instead, you would usually use the ActualWidth and ActualHeight properties, as in this UserControl (which perhaps does exactly what you intended):

public partial class DrawingControl : UserControl
{
    public DrawingControl()
    {
        InitializeComponent();
    }

    protected override void OnRender(DrawingContext drawingContext)
    {
        base.OnRender(drawingContext);

        drawingContext.DrawEllipse(Brushes.Black,
            new Pen(Brushes.Black, 1),
            new Point(ActualWidth / 2, ActualHeight / 2),
            ActualWidth / 2, ActualHeight / 2);
    }
}

OTHER TIPS

Here is the sample i did,

  public MainWindow()
    {
        InitializeComponent();

        var canvas = new Canvas();
        Content = canvas;

        var element = new DrawingVisualElement();

        canvas.Children.Add(element);
        CompositionTarget.Rendering += (s, e) =>
        {

            using (var dc = element.visual.RenderOpen())
                dc.DrawEllipse(Brushes.Black,
               new Pen(Brushes.Blue, 3),        // Border
               new Point(120, 120), 20, 40); 
        };

        Mouse.Capture(canvas);
        MouseDown += (s, e) => Mouse.Capture((UIElement)s);
        MouseMove += (s, e) => Title = e.GetPosition(canvas).ToString();
        MouseUp += (s, e) => Mouse.Capture(null);


    }
    class DrawingVisualElement : FrameworkElement
    {
        public DrawingVisual visual;

        public DrawingVisualElement() { visual = new DrawingVisual(); }

        protected override int VisualChildrenCount { get { return 1; } }

        protected override Visual GetVisualChild(int index) { return visual; }
    }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top