Is InvalidateVisual () possible for a given scope instead of the entire WPF control?

I have a complex WPF control that draws a lot of primitives in OnRender (this looks like a map). When a small part of it changes, I would only like to re-issue the rendering commands for the affected elements, instead of launching the entire OnRender. Although I am well versed in the performance of the OnRender function when resizing, etc., it is not fast enough to highlight mouse-based primitives.

Currently, the only way I know how to force a screen refresh is to call InvalidateVisual (). Unable to send to the dirty area of ​​the rectangle to invalidate.

Is the lowest granularity of WPF screen composition a user interface element? Do I need to do my renderings of primitives in an intermediate target, and then use this InvalidateVisual () property to update on the screen?

+7
user-interface wpf rendering
source share
3 answers

When you want to write custom / composite WPF controls, you should try to avoid overriding OnRender as much as possible, especially if you plan to nullify parts of it. It is much easier to use AddVisualChild + override VisualChildrenCount + override GetVisualChild + override Measure and Arrange like this (pseudocode with two children):

private void BuildMyControls() { AddVisualChild(subControl1); AddVisualChild(subControl2); } protected override int VisualChildrenCount { get { return 2; } } protected override Visual GetVisualChild(int index) { if (index == 0) return subControl1; if (index == 1) return subControl2; return null; // should never be called in fact... } protected override Size MeasureCore(Size availableSize) { base.Measure... BuildMyControls(); .. measure them, probably call subControlX.Measure(...); } protected override void ArrangeCore(Rect finalRect) { base.ArrangeCore(finalRect); ... arrange them, probably call subControlX.Arrange } 

With this code, you can only invalidate one part with something like subControlX.InvalidateXXX ();

+3
source share

WPF doesn't work that way, so you cannot invalidate regions. However, there are some optimizations that can be made. Have Measure, Arrange, and then Skip. If the control moves, but what actually renders does not change, you can tell WPF to just go to the arrangement. You can disable these deviations from changing the value of dependency properties using FrameworkPropertyMetadata and FrameworkPropertyMetadataOptions ( http://msdn.microsoft.com/en-us/library/system.windows.frameworkpropertymetadataoptions.aspx ).

0
source share

You should not use InvalidateVisual() unless the size of your control changes, since it causes a rather costly reinstallation of your user interface.

WPF is a saved drawing system. This means that OnRender() better called AccumulateDrawingObjects() . It actually accumulates a tree of living drawing objects, which should be executed only once for the layout. He then uses these objects to paint your user interface when necessary. To change how a part of the user interface looks like without re-arranging, some objects (for example, DrawingGroup, RenderTargetBitmap and WriteableBitmap) can be updated after OnRender() at any time convenient for you.

To update part of your interface later, wrap these commands in a DrawingGroup and place this object in a DrawingContext . You can then Open() and update it whenever you want, and WPF will automatically repaint this part of the user interface.

It looks like this:

 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(); } 
0
source share

All Articles