6

We have a very large child control which does a lot of rendering to display its detail, but since only a portion of that control is actually visible (it's clipped by something further up the hierarchy, not necessarily its immediate parent) we only want to render the visible portion during the OnRender call.

Consider the following picture. The child is 100x50 but the visible area is a rectangle with corners at (10,5) and (100,50) in child coordinates. That's the area we're looking for.

Clipped Child

Note: You can't simply do coordinate conversions from the child to the parent and test for clipping because it may not be the parent that's doing the clipping.

Consider nested Canvas controls inside a ScrollViewer. The inner Canvas may very well lay completely within the bounds of the outer Canvas, but the outer Canvas may be clipped by the ScrollViewer, thus the inner Canvas is visually clipped by it as well.

Walking the visual tree and testing each parent would kill performance.

So is there anything built in to WPF that can get the bounds of the visible area of a control?

Mark A. Donohoe
  • 28,442
  • 25
  • 137
  • 286
  • This thread might help you get what you want: http://stackoverflow.com/questions/1517743/in-wpf-how-can-i-determine-whether-a-control-is-visible-to-the-user – JimSt24 Dec 19 '12 at 15:59
  • Nope! That's just bounds-checking (see my 'note' above.) That doesn't actually represent what's visible. – Mark A. Donohoe Dec 19 '12 at 17:20
  • Just a stab in the dark - use reflector to look into the internals of IsMouseDirectlyOver property (found on most WPF controls, probably inherited from FrameworkElement). That property looks through nested objects to determine whether the mouse is directly over the exact specific control. I'm thinking that you might be able to use similar logic for bounds checking... – Marko Mar 08 '14 at 21:42

1 Answers1

0

I would suggest that, in general, within your OnRender method you should compose or render your visible items with careful attention to their Z-order, but not necessarily spend time worrying about what's visible. This is not C++. Part of the reasoning behind the design of WPF is that the system should be able to decide for you, what is visible and what is not. It's intended to be a somewhat higher level of abstraction. If you find that you're writing code to test for what is visible, and what the bounds are of that visible portion -- you're probably not using it correctly. Be.. a bit lazier. This (what you described above) is supposed to be quite simple.

As your visible objects slide around, or move about in verticle order (ie, Z-order) -- they will simply become visible, or not. If you want something to be not-visible despite it's position within the Z-order, then you make it invisible (ideally, by binding it to a property that evaluates to Visibility.Visible, Visibility.Hidden, or Visibility.Collapsed).

Also note: when looking at various implementations of graphics -- especially for developers coming to WPF from other platforms, I often find that there was actually no need to override OnRender. Unless you have a lot of graphics that has to be rendered in realtime, you can often let WPF do the work for you and just define what you want to display within your XAML.

JamesWHurst
  • 493
  • 8
  • 14
  • Those are all great points, but they don't apply. We *are* doing a lot of custom rendering which simple (or even complex) bindings can't take care of as they can consist of hundreds of calculations before the rendering actually happens. But their clip area can change based on other factors, so we're spending a lot of time rendering things that aren't ever seen. You're essentially proposing an alternate solution to a different question, not mine. My question was to find a way to determine the clipped area. Thanks for your input though. I'm sure it may help others. Just not us. – Mark A. Donohoe Apr 14 '14 at 05:47
  • And for the record, yes, I know in WPF, unless you're dealing with say, the any 'rendering' in the OnRender call isn't really rendering at all, but rather caching drawing instructions which are then later executed during the actual calls rendering to the hardware. For the point of this question, assume we're using a WriteableBitmap which we must re-generate in its entirety very frequently, so if something isn't actually visible, we want to optimize that portion out. – Mark A. Donohoe Apr 14 '14 at 05:53
  • Ok, I see. Most Q of this type are from devs relatively new to WPF or for simpler scenarios - clearly not the case here. I don't know of a generalized shortcut. I've done 2 that did require a massive amount of complex rendering: in one, the content was to slide across horizontally (a scrolling set of graphs). So I used WritableBitmaps organized conceptuablly in the form of strips, stacked horizontally. As each strip slid off to the left out of sight, it would be marked as off-screen, and visa-versa as strips come into view on the right. It depends entirely upon the geometric nature of the app – JamesWHurst Apr 18 '14 at 18:33