Drag&Drop-adorner in deeply nested visual trees - c#

We have a WPF application that has custom windows on a canvas which in turn contain custom controls (the main canvas containing the custom windows is again custom control displaying stuff). So basically the visual tree looks like this (without implicit Borders and other things):
- Windows
- Canvas
- WindowMgr
- CustomWindow (maximized with z-index 0, functioning as background)
- ScrollPresenter
- CustomControl1
- CustomWindow
- ScrollPresenter
- CustomControl2
Now we need drag&drop from those custom controls to each other (usually from a movable window to the background window). To show the drag&drop adorner an adorned element and an adorner layer is needed. Usually examples use their grid or itemscontrol for that, and also get the adorner layer from the same element.
Doing the same here doesn't work since the ScrollPreseneter/CustomWindows clip their content which prevents you from dragging out of the window. For now we walk up the visual tree until we find the root canvas and use that as adorned element, but that seems kind of dirty (and as we experienced isn't very robust).
Any suggestions on a robust solution for this?

If I read your question correctly and since you didn't mention it yourself you might be looking for the AdornerDecorator Class, which Provides an adorner layer for elements beneath it in the visual tree.
Assuming from its name that ScrollPresenter is derived from ContentPresenter, it's worth noting that for implementing advanced custom controls you might want to surround their ContentPresenter by an AdornerDecorator, just like the Window Class does, see for example Don’t forget the AdornerDecorator for a nice real work scenario involving drag&drop too.
That is, by means of the AdornerDecorator you'll ensure the required AdornerLayer to be contained within your custom control, hence removing the need to retrieve it elsewhere by walking up the visual tree, e.g.:
<ControlTemplate TargetType="{x:Type CustomWindow}">
<Border ...>
<Grid>
<AdornerDecorator>
<ScrollPresenter ... />
</AdornerDecorator>
</Grid>
</Border>
</ControlTemplate>
Depending on your particular scenario you might need an AdornerDecorator for your custom windows, your custom controls or both.
See Adorners Overview for more details on the adorner architecture.

Related

WPF - Docking content inside ContentPresenter

The Circumstances
I'm building a plugin for a WPF application. The parent application has a ContentPresenter and my plugin returns a UserControl. When the parent app runs, it loads up my plugin and places my UserControl inside the ContentPresenter.
The Problem
The problem is that my UserControl is not resized to fit within the ContentPresenter, so when the ContentPresenter is too small to show everything, my UserControl is simply cut off. If the app is resized so that the ContentPresenter becomes bigger than my UserControl, then I get a bunch of whitespace around my UserControl.
Basically, I want my UserControl to act as if it was inside a DockPanel.
What I've Tried
Both the ContentPresenter and the UserControl have Horizontal and Vertical alignments set to Stretch already.
I can achieve the desired result if I wrap my UserControl in a ViewBox, but I don't really know if that's the right way to do it. It feels like I'm missing out on some basic layout principle (which might just be a holdover from my Winforms days). Is there any "proper" way to achieve a docking effect within a ContentPresenter element?
EDIT: I want to emphasize that this is not a ContentControl vs. ContentPresenter issue. I cannot change out the ContentPresenter element because it is part of the parent application. The only thing I can control is the contents of my own plugin which are being placed within the ContentPresenter element. The developers of the parent application might allow me LIMITED access to the ContentPresenter if I need to adjust a property by traversing up the visual tree at runtime, but they've already stated that they don't want plugins navigating outside of their own scope of controls. This isn't as much of a technical limitation as a their-terms-and-conditions-won't-allow-it limitation.

Moving Control over a ScrollViewer

I'm developing a small WPF application which uses a ScrollViewer to show an Image in a Window.
I have generated the window and all his relative code (I will show it if needed but I think is not usefull for the point of this question) programmatically.
The question/ how to is the following. I have to show/hide (pressing a button) a control (basically a InkCanvas) over the image contained in the ScrollViewer. Except the part oh show/hide is pretty simple to use the button event) which is the best way to add a control (and which type of control/container) at the Window forcing him to be over the ScrollViewer and then be able to move around dragging it?
I'm relatively new to WPF I used a lot of WinForms (I can do this in WinForms but WPF is a new world for me).
Thanks in advance!
As for the container you should use a Grid which will center and put on top of each other the controls in a same cell.
As for drag and drop if you want to implement it yourself I've provided a minimal implementation here: https://stackoverflow.com/a/17014906/145757
Otherwise you can use the MouseDragElementBehavior behavior provided by Blend.
Here is a tutorial that demonstrates its usage from Blend itself: http://www.c-sharpcorner.com/uploadfile/nipuntomar/expression-blend-4-behaviors/
But you can use it without Blend by importing the Blend libraries and using it from your XAML with something like:
<InkCanvas ...>
<interactivity:Interaction.Behaviors>
<blendbehaviors:MouseDragElementBehavior />
</interactivity:Interaction.Behaviors>
</InkCanvas>
with interactivity and blendbehaviors being mapped to the Blend namespaces.

Dynamic layout of WPF controls which depends on some condition

I'm using WPF and I have a problem with layouting. I have got a docked panel (non WPF, I just hosted my control inside). And when a user wishes to dock this panel on the left or the right of the screen, I need to layout my controls in one way. But when the user wishes dock this panel on top or bottom, I need to layout my controls in another way.
My question is what is the best way to implement dynamic layout of WPF controls, which depends on some conditions?
I understand, that I can use the grid and dynamically change positions of my controls inside the grid. But I am not really happy with this solution. I'm looking for a solution with no code intervention, xaml only. And in case this is impossible, at least involving minimum intervention in the code.
Thanks in advance.
You could use AvalonDock to get a docking system very much like visual studio's.
This would give your users full control on the layout they desire, and it's not too hard to implement.
But if you really want a quick way to do this, I'd recommand Binding the DockPanel.Dock property to a ViewModel value that changes upon user input (along with an IValueConverter if necessary).
For this purposes DataTemplate feature is.
The idea is to provide multiple DataTemplates and then using your custom inplementation of the DataTemplateSelector rturn right DataTemplate based on criteria.
For an example see my post regarding DataTemplates
Data Templating Overview
Use StoryBoard and change the transformation of controls

How do I use parent's ItemsHost for HierarchicalDataTemplate in XAML?

I have a tree- or menu-like data structure which I want to display in a Panel (specifically a self-made PolarPanel), but all items must be VisualChildren of the same panel.
If I define a HierarchicalDataTemplate, I need to create an ItemsControls and specify it as IsItemsHost, or am I mistaken here? Can I somehow reference the parent's ItemsHost?
<HierarchicalDataTemplate
DataType="{x:Type local:ItemsCollection}"
ItemsSource="{Binding Children}"
>
<!--/* "virtual" ItemsHost referencing the parent's ItemsHost? */-->
</HierarchicalDataTemplate>
(My first workaround was to have a GetAllTheChildren property in the root node which returns all children and all children of the SelectedChild, recursively. This doesn't easily work together with ObservableCollection, because changes have to bubble up to the root to refresh GetAllTheChildren again (which reloads more items than would be neccessary).)
I know I can do it in code-behind by creating and drawing the items' Views into the same parent, but I'm searching for a nice WPF, indirect, automagic way.
EDIT: I am now using an improved workaround, where all ItemControls / Panels are drawn on top of each other. This preserves the hierarchical aspect, which makes this a much better solution than the one mentioned above (with GetAllTheChildren). But it still doesn't answer my question...
This is what it looks like graphically:
Note how the hierarchical elements have to be arranged in the same space.
Is there a clean and simple solution to this?
I must admit that the graphic result is very attractive, even I wouldn't know how to use that kind of control!
To answer to your question, I never tried to share the same panel as host, but I don't think would be possible. That would break the visual tree hierarchy schema. Any visual element cannot have more than a parent.
Assuming that every hierarchy level maps his own ring, I surely bet on the classical way to create such a composite UI. There's no doubt about the convenience of using the HierarchicalTemplates and ItemsControls, even it could be a complex task.
Moreover, I don't understand whether your goal is to have some kind of collapse, such an ordinary tree-view. In this case, avoiding the classical WPF approach would be a nightmare!
My solution is to create a custom panel, being able to arrange their children on a ring.
That's not all. It must be created both a custom Control and an ItemsControl. The first one will represent the ring-slice that has to be rendered, and the other just as the generator.
The control acting as item holder will have two properties: angle and radius. The thickness can be set apart.
The panel, calling MeasureOverride, must take in account the ring nesting, and set both the angle and radius of their children accordingly.
From my viewpoint, the holding control should derive from a ContentControl. That because you need to render the shape of the slice, and that task should be done by this control. Any particular embedded control (text, buttons, etc) can be placed inside as content.
Of course, all that is brainstorming. I'm not guarantee that is the best solution, nor that would work as is.
Hope it helps.
Cheers

How to reuse WPF ScrollViewer to create my own scrollable control?

I'm trying to improve the graph drawing control that comes with Graph#. It's good, but things get out of hand when you start dragging nodes around. This is my first encounter with WPF, so this is probably a newbie question. :)
I have the GraphCanvas control which has nodes and edges on it. They can be dragged around which changes their coordinates, possibly making them negative. I would like to add scrollbars to the control which would allow to see how big the canvas really is.
To this end I'm thinking of putting the GraphCanvas inside a ScrollViewer. Which would be pretty easy and straightforward if not for one problem. I may not resize the GraphCanvas itself when a node is dragged outside the borders or this will mess up dragging bad. That is also the problem with the original control (check it out, it comes with a sample application).
It would be good if I could bind the scrollbar size/location to properties of the GraphCanvas, so that the ScrollViewer would not scroll anything physically, but just set the properties of GraphCanvas. That in turn would perform all actual calculations and scrolling.
How can this be done?
OK, I found it! Three easy steps:
Implement System.Windows.Controls.Primitives.IScrollInfo on your custom control;
Add your custom control to a ScrollViewer;
Set the CanContentScroll property on the ScrollViewer to True.
Voila!
Check out this link straight from MSDN. It talks about composing several controls into a single Composite Control:
WPF: Customizing Controls for Windows Presentation Foundation

Categories