views:

63

answers:

2

We have a WPF application (.Net 4.0) using a Docking Control (Actipro). We can dock out the docking windows. In that case, a "real" Window is created and the content is assigned to that window.

Of course, moving stuff in the Visual Tree will re-trigger the complete layouting. This is problematic, because in one of these docking windows, we have a diagramming control (Mindfusion Diagramming,WPF control) that can take up to 10 seconds to completely layout itself (very large diagrams).

I don't think that there's any direct solution to this problem. I wonder however how other programmers with similar issues approached this problem. Is there any clever way to avoid recalculating the layout?

In theory, nothing really changes since the diagram is inside a ScrollViewer, so whenever it is placed, the amount of avaiable space remains the same(infinite).

Edit: Also note that the diagram control inside is interactive. We need Drag&Drop.

A: 

you might want to replace your diagramming control in the visual tree with an Image, render the diagram offscreen and use rendertargetbitmap to convert the rendered diagram to an image, which you can use as the source for the Image in the visual tree.

something like this:

// image is the Image from the visual tree
int h = image.ActualHeight;
int w = image.ActualWidth;

// layout the diagram to the size of the image
diagram.Measure(new Size(w, h));
diagram.Arrange(new Rect(newSize(w,h)));
diagram.UpdateLayout();

// render the diagram to a bitmap
RenderTargetBitmap bmp = new RenderTargetBitmap((int)w, (int)h, 96, 96, PixelFormats.Default);
bmp.Render(diagram);

// set the source of your image to the bitmap
image.Source = bmp;

in the example if PixelFormats.Default doesn't seem to work, you might try PixelFormats.Pbgra32, which I think is a more common format to use in this type of thing.

you might also be able to use a VisualBrush in a similar manner. I can imagine in the long run you could probably create a wrapper class for the diagram to automatically display the image copy and re-layout the diagram only if something changes (ie a part of the diagram or the size).

Mark Synowiec
Alex Maker
Gotcha, neither of these would fit your situation then. If I think of anything else, I'll repost. Good luck!
Mark Synowiec
Thanks. I'm gonna need that. It sounds impossible to accomplish what I want, but you never know if there isn't some genius out there. Our app is almost ready and this problem is the last thing holding us back, and we just don't find a way to solve this. All our beta users are dragging the diagram docking window out and think "WTF?! Has the app crashed?".
Alex Maker
+2  A: 

Here is an idea.

  1. Create a custom class inheriting from Decorator.
  2. Wrap your diagramming control inside the decorator.
  3. Override MeasureOverride and simply call base.Measure but store the result in a field before returning.
  4. Add a property which enables you to disable the measure call. If the property is true simply return the previous size in MeasureOverride instead of calling base.Measure.
  5. Set the property while changing the visual hierarchy.

From the top of my head I can't think of any reason why this shouldn't work.

I have actually done something very similar not too long ago. When implementing the sliding animation for the side panels in NovaMind I used a Decorator to prevent the content from performing layout while the panel animates its width. I calculated the size with the final width, stored it and then used MeasureOverride to fake the current size... This prevented the performance issues involved when trying to animate the width of a complex control. :)

Patrick Klug
Unfortunately, this is not the right solution for this case. The diagram is moved into a new window (I make the docked window a floating window, hence the docking control is creating a new window and moves the content to it). If I could however vote you up I would, because the answer is still useful (I'm gonna keep it in mind until the day I come across such a case).
Alex Maker
I am not sure why it wouldn't work in this case. If you know when this happens you could set the flag and the docking library would take your decorator and move it across... or am I missing something?
Patrick Klug