Home > Software design >  Forcing a DrawingVisual to redraw
Forcing a DrawingVisual to redraw

Time:08-22

I'm trying to draw a random sqaure using the DrawingVisual class, and a "New Square" Button to replace the square with newly generated one.

I'm not able to figure out how to Force the DrawingVisual to redraw.

I'm not looking for alternative solution, I just want to know if it's possible to change a DrawingVisual after it's been instantiated

Here's my current Code:

     <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="200"/>
        </Grid.ColumnDefinitions>

        <local:RandomSquare Grid.Column="0" x:Name="randomSqare"/>
        <Button Grid.Column="1" Content="New Square..." Click="Button_Click"/>
    </Grid>

Here's me trying the InvalidateVisual method

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

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            randomSqare.InvalidateVisual();
        }
    }
    public  class RandomSquare : UIElement
    {
        private DrawingVisual _visual;

        public RandomSquare()
        {
            _visual = GetRandomSquare();
        }

        private DrawingVisual GetRandomSquare()
        {
            Random rnd = new Random();
            int xy = rnd.Next(200);
            int size = rnd.Next(200);

            DrawingVisual visual = new DrawingVisual();

            using (DrawingContext context = visual.RenderOpen())
            {
                context.DrawRectangle(Brushes.AliceBlue, new Pen(Brushes.DarkBlue, 1), new Rect(xy, xy, size, size));
            }

            return visual;
        }

        protected override int VisualChildrenCount => 1;

        protected override Visual GetVisualChild(int index)
        {
            return _visual;
        }
    }

Thanks

CodePudding user response:

It is not working because

randomSqare.InvalidateVisual();

does not magically call the GetRandomSquare() method.

That method is called only once when the RandomSquare element is created, i.e. during the InitializeComponent() call in the Window constructor.


You may instead draw into the DrawingContext that is passed to an overridden OnRender method:

public class RandomSquare : UIElement
{
    private readonly Random random = new Random();

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

        int xy = random.Next(200);
        int size = random.Next(200);

        drawingContext.DrawRectangle(
            Brushes.AliceBlue,
            new Pen(Brushes.DarkBlue, 1),
            new Rect(xy, xy, size, size));
    }
}

When you want to use a DrawingVisual, you need to call AddVisualChild in its UIElement parent. You would also have to declare an explicit method for updating the DrawingVisual.

public class RandomSquare : UIElement
{
    private readonly DrawingVisual visual = new DrawingVisual();
    private readonly Random random = new Random();

    public RandomSquare()
    {
        AddVisualChild(visual);
    }

    protected override int VisualChildrenCount => 1;

    protected override Visual GetVisualChild(int index) => visual;

    public void Update()
    {
        int xy = random.Next(200);
        int size = random.Next(200);

        using (var drawingContext = visual.RenderOpen())
        {
            drawingContext.DrawRectangle(
                Brushes.AliceBlue,
                new Pen(Brushes.DarkBlue, 1),
                new Rect(xy, xy, size, size));
        }
    }
}
  • Related