Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Possible to InvalidateVisual() on a given region instead of entire WPF control?

I have a complex WPF control that draws a lot of primitives in its OnRender (it's sort of like a map). When a small portion of it changes, I'd only like to re-issue render commands for the affected elements, instead of running the entire OnRender over. While I'm fine with my OnRender function's performance on a resize or whatever, it's not fast enough for mouse hover-based highlighting of primitives.

Currently the only way I know how to force a screen update is to call InvalidateVisual(). No way to send in a dirty rect region to invalidate.

Is the lowest granularity of WPF screen composition the UI element? Will I need to do my renders of primitives into an intermediate target and then have that use InvalidateVisual() to update to the screen?

like image 795
scobi Avatar asked Apr 05 '10 02:04

scobi


1 Answers

When you want to write WPF custom/composite controls, you should try to avoid overriding OnRender as possible especially if you plan to invalidate portions of it. It's much easier to use AddVisualChild + override VisualChildrenCount + override GetVisualChild + override Measure & Arrange like this (pseudo code with 2 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 kind of code, you can invalidate just one portion, with something like subControlX.InvalidateXXX();

like image 51
Simon Mourier Avatar answered Nov 16 '22 14:11

Simon Mourier