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.
Related
I've thoroughly checked the custom controls topic, spent several hours looking into custom controls written by other people. I've written my own custom button, to feel it better. I've read all the google answers around the "why custom controls", "advanced custom controls examples" and such.
My question is, WHY?
Why would I (or anybody) go through 9 circles of hell to create his own custom control, when one can just adjust an existing control to his needs (using styles and templates). I actually didn't find any explanation on google, just tons of examples, mostly from people who sound even less educated than me.
I imagine there IS such need, when talking about some complicated DataGrid with, I don't know, every cell being a button or something (and still I believe I could do it with a regular DataGrid)... But I've not found anything more complex than a beautiful button. Is there nobody sharing a complicated code on the topic?
There are different levels of element customization in WPF, depending what class you extend from. Each has its own uses and is implemented differently. It is not clear from your question if you are asking about a specific type of control or about all of them in general. So, I will tell you what I think about different ones.
UIElement or FrameworkElement
Extending UIElement gives you the lowest level custom control where you have complete control over the layout and rendering. FrameworkElement is slightly higher level as it does most of the common layout stuff for you while also allowing you to override key parts of it. The main idea with these is that they do their own rendering rather than composing other elements together.
I have made a number of custom FrameworkElements over the years. One example is a ruler similar to one you might find in a program like Photoshop. It has a bunch of properties providing customization for how it is displayed as well as showing markers indicating mouse position relative to the ruler (and a number of other little optional features). I have used it in two different professional projects. I think the main benefit is that it is extremely easy to drop in and set properties/bindings on wherever desired. Build it once, use it over and over.
Control
Extending Control introduces the concept of compositing multiple elements/controls into one reusable component via control templates.
I have used this one less often, but still find it very valuable in the right circumstances. Again, the main benefit here is reusability. You create a control with properties that make sense for what you want to do, then hook up those properties to the properties of the controls in it's control template. Really, this is the same as applying a new template to an existing control, with the added feature of being able to define your own dependency properties. You also have the ability to perform custom logic in the control's code if you need to.
I may be misreading some of your text, but you seem to imply that making a custom control is considerably more difficult than making a control template for an existing control. I have found that the two are nearly identical in most cases using this approach, the only difference being whether you have a code behind you can use.
User Control
A user control is really only slightly different from a custom control practically speaking. Only, instead of defining a control template, you define the visual content directly.
This is probably the most common type of custom control. It is basically the standard method for making XAML based content in a WPF application. These can be reused like other controls, but are more suited for single use such as the content of a dialog or window or something else that is specific to a single application.
Some Other Control
You can also extend an existing control to add additional functionality to it. This way, you still get all the features the control offers and only have to implement the additional bit.
For example, I have a custom control called an AutoScrollRichTextBox that extends RichTextBox. So, it does everything a RichTextBox can do. It also has the ability to automatically scroll to the bottom when content is added to the text box (which it only does if the text box was already scrolled to the bottom before the addition content was added).
I could have implemented that feature as an attached property instead of an extension of the control (and maybe I should have), but it works, and I have used it in three different applications (as an output window and as a chat log). So, I am happy with it.
In the end, it really is just a matter of how self-contained, reusable, and easy to drop in you want a control to be. If there is already a control that does what you want, and you just want it to look different, then you should definitely use styles and templates to achieve that. However, if you want to make something that doesn't already exist, limiting yourself to using only styles and templates will make the implementation work harder and make the end result less reusable and more difficult to set up additional instances (unless all instances are identical).
The examples of making things like buttons that look different are not examples of what you should use a custom control for. They are just examples of how someone would go about making a custom control for the purpose of teaching the details of the process. If you actually want a customized button, just customize a button.
I need to develope a WPF custom control to show the layout and connectivity of nodes in a wireless mesh network. The user needs to be able to drag the nodes around. The canvas should grown and Scrollbars should appear as required if elements get draged off the available space. The ability to zoom in/out might be required.
My first take on this is to use a ListBox derived CustomControl with a Canvas based ItemsPanelTemplate. To get things moving Im using Josh Smiths DragCanvas that allows UIElements children of the canvas to be dragged around. My "node" class is not currently UIElement derived (the DragCanvas is currently working with the ListBoxItems that wrap my nodes).
1. Is this a bacially sensible approach or should I be abonding the ListBox idea and going something lower level?
2. I have to overlay the inter node link lines - not currently sure how to go about this (as a UIElement class that is part of the ControlTemplate?)
3. A few people seem to be having a headache with scrolbars in Canvases - is this going to be an issue?
Any general or specific advice most appreciated.
Wow, not bad as a control!
I am doing something similar, but it is not so simple.
1) IMHO, the DragCanvas is a basic way to host+drag elements. Since you will have to host labels (nodes), arcs and labels again (arcs' weight), I think the DragCanvas would be harder than write a custom control by yourself.
Not everything comes easy with templating: sometime is much better the "old" approach winforms-like, or even a hybrid way.
2) As stated, I'd create a Canvas-derived panel, which will host several UIElements (labels, arcs, etc). All of them should be governed by a model+viewmodel. That's a bit harder at the beginning, but it will give you a lot of satisfaction and flexibility in the future.
3) I don't think the Canvas will give you any headache! A Canvas full of elements has always a size of zero. That leads "headaches" for those trying to add a scrollviewer.
Instead, the Canvas-derived class (above) should override the MeasureOverride method, so that its size will fit any of the hosted objects. However, it is a bit annoying the fact you cannot use negative coordinates (it will cause scrolling problems).
It's hard to describe in few lines all the work behind a similar "editor". The task isn't easy, and the problems are many.
Hope it helps, anyway.
Cheers
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).
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.
I asked a similar question about this previously, but I did not specify that this needs to work in Partial-Trust mode. Unfortunately both correct answers (using UIElement.BitmapEffect or UIElement.Effect) are not allowed in Partial-Trust, because it requires UIPermissionWindow.AllWindows.
Does anyone know of a way to do something similar to the OuterGlowBitmapEffect in a Partial-Trust app?
If you need a rectangle outline, you can attach an Adorner with a simple rectangle in it. It's not going to have the glow effect you are looking for, though.
If you need a non-rectangle outline, you can still use Adorner, but you also need to specify opacity mask, based on a visualBrush on your object. You will also have to make the adorner a little bit bigger than the source visual, to make it look like it surrounds the object instead of overlapping it.
If you want to go fancy, you can encapsulate attaching the adorner in an attached dependency property and just attach it to any visual you need to outline.
If you don't want to bother with adorners, you could have two separate templates for you visual - one with the outline pre-created and one without and switch them as needed. However, this requires you to know upfront what cvisuals you would need to outline and what is their style. Granted, you can make it quite flexible with data binding, but still it's not a generic solution to your problem.