Move UIElement in Visual Tree without recalculating layout - wpf

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.

Here is an idea.
Create a custom class inheriting from Decorator.
Wrap your diagramming control inside the decorator.
Override MeasureOverride and simply call base.Measure but store the result in a field before returning.
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.
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. :)

Another possibility is that the problem isn't related to layout so much as the "severing" of the visual tree when moving the content from one window to another. This seems to cause a slew of recalculations for dependency properties, which if your visual tree for content was like mine, upwards of 2000 controls, it was really slow.
I couldn't find an elegant solution to this using Actipro docking library itself, so I thought how I could divert WPF from doing this behavior. The solution I came up with was to create my content as a single WinFormsHost control with a single child of a WinForms UserControl. Then, I made that WinForms UserControl have it's content be the WPF based content that should appear as the docking window content. I figured that when WPF started walking the visual tree from the top to re-evaluate all dependency properties when the tree was "snipped", it would run into the WinForms control and stop.
My Actipro docking tool windows used to take 6 seconds or so just to switch tabs or to float. Now they are essentially instaneous. You have to ensure that any command handlers are not at the application level, but instead at your WPF content level and you might have to finagle wtih the location of some style files, but it worked fantastic.

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).

Related

Win32 C - Control IDs of dynamically created controls?

I'm trying to create popout windows (like the dockable panes in Visual Studio). I need to create splitter controls to allow resizing of the controls when they're attached. I'm basing my design around the MFC docking panes and I'm trying not to hardcode docking regions.
Ideally I'd not like to have a fixed amount of sliders that are created hidden, but rather a variable amount depending on the location of each attached window. My current thoughts:
Use SubtractRect() to subtract the RECT of the attached window from that of the effective client area.
Create a slider for each edge of the control that is not on the edge of the main window's effective client area.
However when using CreateWindow() ideally a control ID would be passed in which is usually hard-coded in Resource.h, which then makes dynamic creation of controls tricky. Not to mention recalculating window sizes based on the location of the slider(s).
I'd thought about allocating an ID range to use for dynamic controls so I could start off with #define IDC_SPLITTER1 100 for example, then increment from this value for each splitter created. I've seen _APS_NEXT_RESOURCE_VALUE mentioned which I believe is used in MFC, but only for the IDE?
Sorry if this question is a bit wish-washy, I'm really struggling to get my head around this.
Thanks.

WPF Custom Control with Databinding

I'm looking to create a custom control which represents a hand.
This at needs to be bound to a datasource, then if a value/index value is present in the datasource which is representing a particular finger, the finger in question should appear green.
Can anyone point me in the right direction to start of with such control?
Basically I'm creating an app which records which fingers people where their rings and how many.
So graphics on each finger will show Green plus a number showing how many.
Rough Hand Design for User Control
Any help or direction will be mostly appreciative.
I'd recommend a usercontrol rather than custom control for this. As I think that link Clemens posted says, unless you really are going to switch out the template of the control then you don't need to do a custom control - which would be harder than a usercontrol.
This will have at least one dependency property you're going to bind your collection to. Make that an ObservableCollection. You can then pass say 0,1,0,2,0. If people change the rings they wear super dynamically you can set one of the collection to itself to cover change notification to the control.
Inside this I'd put a viewbox with a canvas in it.
Grab an outline of a hand from somewhere. You want to get a geometry out of this so look for a svg preferably.
Maybe https://www.flaticon.com/free-icon/stop-hand-silhouette_57659
Then download and install InkScape.
Use this to trace bitmap if that's all you have then save as > xaml.
Open that file in notepad and you'll see a path with a set of sort of co-ordinates. Grab those. These can be used to define a geometry you use as a resource or directly used as the Data to a path.
I use such a resource for the email "icon" in this:
https://social.technet.microsoft.com/wiki/contents/articles/32610.wpf-layout-lab.aspx
Or you could probably use one of the hand icons from syncfusion's metro studio ( free ) https://www.syncfusion.com/downloads/metrostudio
A Path can be used for your hand.
You then want 5 itemscontrols for your thumbs and fingers.
You could maybe make each of them a usercontrol as well but I'd try 5 controls for a first iteration.
They should template each item they're given into a green rectangle defined in itemtemplate.
Position 5 of them to taste on your hand's digits.
Bind their itemssources by index to your collection and use a converter to return the number of objects specified by that. So if it's 3 then you generate three objects.
That viewbox is there to scale everything. So you can size your control however you like and the rings will stay on the fingers.

When should I use adorners?

WPF is great because there are many ways to achieve your goals. For example, from what I understand, adorners can add some controls to a UI element, but I think that the same behavior can be achieved through a custom control that contains the additional element.
So, my question is: when should I prefer adorners to a more complex (but I think, more flexible) custom control?
Please consider that I'm extensively using MVVM pattern and I would like to bind commands to the additional element.
In particular, I'm designing a diagram designer application and I would like to add connection points to my shapes. Another example where I should decide between a custom control and an adorner is a line which shows a label automatically positioned to "follow" the line.
Thank you
Adorners require a little more work than using ControlTemplates for most purposes. If you want the additional functionality that adorners provide, use them. Otherwise use ControlTemplates.
Here are the main features that Adorners bring to the table:
Because adorners are on a separate layer, the visual can extend beyond the adorned element, even if the adorned element is clipped.
Because adorners are on a separate layer, they are generally not obscured by the AdornedElement's container or by sibling controls.
Adorners are automatically notified of all changes in the size and location of the adorned element, allowing responses to layout changes that are not as easily achieved with ordinary controls.
Adorners can be applied to panels and to existing controls without making any changes to their templates or otherwise. This makes them good for providing manipulation handles or visual feedback on arbitrary controls.
In many scenarios you will create adorners only for a few "active" items out of hundreds or thousands. Implementing the same functionality using ControlTemplates can be dramatically less efficient if you have to add an additional Panel to the template: Every single instatiation of the template will have the extra panel, whereas there would be just one adorner.
Here are some of the potential costs associated with using adorners as opposed to ControlTemplates:
You must write code to call .GetAdornerLayer() and .Add() and to manage the lifetime of the Adorner
You must either write rendering code for your Adorner or add code to include a Control as a child of the adorner so you can use a ControlTemplate with it
You'll generally do your custom measure/arrange calculations in code (unless you are using a ControlTemplate within your adorner)
You'll need to forward RoutedEvents to the AdornedElement if you want them to be handled by the target control
You'll need to add a DataContext="{Binding AdornedElement.DataContext}" if you want to bring the DataContext across
It appears that visible Adorner is scanned on every layout pass, so having many thousands of adorners onscreen at once can result in noticeable slowdowns. (Ordinary visuals only have their measure/arrange code called when something that directly affects them changes.)
Having more than 144 adorners is not supported, so control templates are more suitable if there's any risk of getting close to this limit.
In your particular examples, there are no clear-cut right answers.
I'd lean toward using a ControlTemplate for connection points since you will presumably need a way to specify the locations of the connection points, and the ControlTemplate is already defining the layout the item itself. On the other hand, if the connection point information is data-driven and only appears on the active control (or the control being dragged over) it might be better to use adorners to get the performance advantages and simplify the individual ControlTemplates.
An automatically positioned label could be a good fit for an adorner from a measure/arrange calculation point of view if the lines are anything but simple straight lines, but if you will potentially have ten thousand of these visible at once I would be concerned about performance.
Without knowing more about your application it is hard to say more than this.

WPF as IHTMLPainter control

I need to host WPF control inside IE, therefore I'm trying to implement IHTMLPainter and IElementBehavior interfaces. I'd like to build my custom behavior and use it inside IE, but the problem is how to draw WPF control by just having IntPtr hdc parameter.
Probably I can get Drawing.Graphics by the following code:
Graphics.FromHdc(hdc);
But I'm not sure that this is the best way. Please advise
I'm assuming you want to be able to make use of the advanced features of WPF within a MSHTML context. In that case, Graphics.FromHdc(hdc); will not do the trick for you. The resulting Graphics object will have no way to receive WPF content because WPF uses a retained-mode system and its MILCore rendering engine uses Direct3D not GDI+.
I'll give you one sure way to use WPF features inside a IHTMLPainter, plus pointers to another way that would likely be faster if you can get it to work.
Bitmap copying solution
An easy solution is to simply copy the background provided by MSHTML into an ImageBrush, use RenderTargetBitmap to let WPF render to a bitmap, then copy it back to the device.
To do this, construct your WPF content in any Visual subclass with a Background property (eg Grid or Border), then in your IHTMLPainter.Draw() method, just do the following:
Create a System.Drawing.Bitmap corresponding to rcUpdate
BitBlt from the given DC into the System.Drawing.Bitmap
Construct an ImageSoure from the System.Drawing.Bitmap (see recent SO answers for details)
Construct an ImageBrush from the BitmapSource using a viewport/viewbox that will lay it behind the portion of the visual corresponding to rcUpdate
Set your root visual's background to the ImageBrush
Set the RenderTransform on the root visual so that the rcUpdate portion starts at (0,0)
Render the root visual to a RenderTargetBitmap of rcUpdate size
BitBlt the RenderTargetBitmap to the rcUpdate area of the DC
This should work well, be simple to implement, and work for any WPF content including advanced features such as 3D, BitmapEffects, etc. The only disadvantage is that those two bitmap copies might slow things down somewhat.
Note that if you know your WPF Visual is totally opaque you can completely skip steps 1-5 and simply render your Visual to a RenderTargetBitmap and BitBlt it to the device.
Direct3D possibility (partial solution)
Obviously it would be faster to avoid all this bitmap copying during render. This is most likely possible, but I can only give you some ideas to point the way -- it will take a lot of trial and error and probably some undocumented calls to make it work.
Since WPF renders using Direct3D, obviously you would prefer to get a Direct3D surface from MSHTML and paint on it. Doing this requires two things: Getting the surface from MSHTML, and getting MILCore to draw on it.
IHTMLPainter has a flag HTMLPAINTER_3DSURFACE to request a Direct3D surface in its GetPainterInfo call, but I couldn't find any examples of how to use HTMLPAINTER_3DSURFACE. I suspect it could be figured out with a little trial and error.
I did not find any way to get WPF's native component "MILCore" to accept a Direct3D surface to paint on instead of a hWnd. There is no documentation on MILCore, and the only public API for setting up rendering tree, HwndSource, doesn't seem to be able to do the job.
Rendering behaviors through IHTMLPainter and IElementBehavior are meant to alter or supplement the display of existing elements in a page, not to render content for user controls. If you're looking to use WPF controls in a page, this is not the path to take. Instead, consider creating a blank windowed UserControl with ActiveX support, then do either of the following.
Add your WPF control at runtime as a member of the UserControl.
Perform WPF activities using the window handle (HWND) of the control.
Alternatively, you could just use Silverlight to make user controls. Silverlight has a pretty good subset of WPF display features, and even manually constructed Silverlight content is easier to manage than trying to get .NET Windows + ActiveX Hosting + WPF working.
If I've mistaken your question and you're truly intent on using WPF to perform drawing activities in an element behavior, Graphics.FromHdc() is an acceptable way to get a usable Graphics object. You should attach to the HDC specified in the Draw() callback.
Draw Method (IHTMLPainter) # MSDN
You could also attach to the window handle (HWND) of the document view (retrieved via IOleWindow), if your WPF activities involve the entire viewport. The window object can be cast to IOleWindow for this purpose (see IHTMLWindow2).
IOleWindow Interface # MSDN
IHTMLWindow2 Interface # MSDN

WPF - Creating simple controls to be used on a Canvas

I'm developing a simple WPF UI for image post-processing.
I'd like to create a draggable WPF control to be used on a Canvas which would look roughly like this:
http://img32.imageshack.us/img32/884/photoeditor.png http://img32.imageshack.us/img32/884/photoeditor.png
Both end points ellipses would be draggable and the line joining them would follow as the end points move.
Now, I know how to implement this by simply adding these elements into a Canvas and then implementing the necessary event handling to make the elements move as they're dragged. But that's hard to maintain if I ever want to add other types of draggable controls.
What I'd like to do would be to isolate all the handling into its own class (say DragLine), derived either from FrameworkElement or UIElement. To add this draggable UI element into a Canvas, I'd create an instance of DragLine and just add it to Canvas.Children. The rest of my program would only see DragLine instances and wouldn't need to worry about the lines or ellipses used to draw the new element.
I'd like to implement the line end points using standard shapes such as the Ellipse rather than drawing all of the UI element myself. That's because I'd like to re-use the event handling and hit testing these shapes already implement.
Question: is deriving from FrameworkElement the right way to go about this? The line and end point ellipses would then be just be visual and logical children of in my new class.
If deriving from FrameworkElement is not the recommended way, how would you go about this instead?
If it is, is there a way to simplify its implementation given that the new class would only ever be used on a Canvas (and doesn't need to work well for things like a Grid or a StackPanel)?
Ah, yes, trying to reinvent things that already exist in the framework because you don't know about them. Its been a hobby of mine for quite some time.
What you are doing here is trying to create a special type of adorner. These are relatively easy to do using the bits that already exist in the framework. I suggest you start here.
Another thing you might want to look at are Decorators. Do pretty much the same thing but I think they are more visual. Which one to use depends on your requirements.

Resources