How to redraw or refresh in OnRender?

2020-02-26 12:12发布

问题:

I want to draw something dynamically. Following code shows my OnRender. I'm setting DrawItem somewhere in my program where I need it. But when I'm calling DrawItem =5; what do I have to call, so that OnRender gets called?

protected override void OnRender(DrawingContext drawingContext)
{
    switch (DrawItem)
    {
        case 1:
            //Draw Item 
            break;
        case 2:
            //Draw Item 
            break;
        case 3:
            //Draw Item 
            break;
        case 4:
            //Draw Item 
            break;
        case 5:
            //Draw Item 
            break;
    }
    base.OnRender(drawingContext)
}

public int DrawItem { get; set; }

回答1:

Your question is not clear but from what I can understand you seem to be asking for a method to refresh the visuals after updating your drawing variables. You could use the following after updating your drawing variables:

this.InvalidateVisual();

and with the property:

private int drawItem;
pulic int DrawItem
{
 get {return drawItem;}
 set 
 {
    drawItem=value;
    this.InvalidateVisual();
 }
}


回答2:

If the size of your control changes, you can use InvalidateVisual(), however keep in mind this causes a fairly expensive re-layout of your UI. If the size of your control is staying the same, you shouldn't call InvalidateVisual().

A more efficient way to update your UI is to create a DrawingGroup "backing store" and add it to the DrawingContext during OnRender(). You can then update it whenever you like, using DrawingGroup.Open(), and WPF will update your UI.

If this sounds confusing, remember that WPF is a retained drawing system. That means OnRender() might better be called AccumulateDrawingObjects(). It's actually accumulating a tree of live drawing objects, some of which (like DrawingGroup, RenderTargetBitmap, and WriteableBitmap) can be updated later.

This is what it looks like:

DrawingGroup backingStore = new DrawingGroup();

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

    Render(); // put content into our backingStore
    drawingContext.DrawDrawing(backingStore);
}

// I can call this anytime, and it'll update my visual drawing
// without ever triggering layout or OnRender()
private void Render() {            
    var drawingContext = backingStore.Open();
    Render(drawingContext);
    drawingContext.Close();            
}


回答3:

I ran into similar issue and found an even more elegant solution. Define a DependencyProperty like so:

public static readonly DependencyProperty PropertyNameProperty = DependencyProperty.Register("PropertyName", typeof(PropertyType), typeof(PropertyElementType), new FrameworkPropertyMetadata(DefaultPropertyValue, FrameworkPropertyMetadataOptions.AffectsRender));

The key here is this:

FrameworkPropertyMetadataOptions.AffectsRender

So now the property can be set in XAML and updates visual automatically on changing.



回答4:

http://msdn.microsoft.com/de-de/library/ms598919(v=vs.100).aspx

You have to call InvalidateVisual for the Control that shall be updated. But as you can read, a call to InvalidateVisual causes a complete layout cycle, so be sure for performance reasons that your canvas or whatever you want to draw on contains no or only a few child elements.