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
Related
I'm creating a WPF program. I want to animate a list of usercontrols to be animated in such way that they seem to move away from the user. Imagine watching the road as cars move away from above them (a little higher than car's roof). I hope this was clear enough. I will try to add a video/GIF if it isn't.
I don't have much experience in WPF animation. Is there any built-in way to achieve this? I searched around but since I don't know what exactly this is called, I didn't have much success.
Silverlight has 3D projection transforms that you can animate, but not WPF unfortunately. You can still accomplish 3D projections though by writing your own animations, or by using 3rd party libraries (for example).
I am new to professional development of UI application. I wonder what the normal approach to decide the layout of the each UI element.
Do people hard-code the size elements according to the design time monitor size? And later scale the UI size dynamically?
Or do people use some dynamical approach to set each UI element proportional according to screen size? I meant if there's a method dynamically to set controls size proportional to screen size and that ratio is hard-coded by programmer. Obviously, Dockpanel or viewbox are automatic adjusting. Or do people usually decided size upon design time?
Or there're other common approach?
Its generally recommended to have size of the elements proportional according to screen size. WPF has lot many features to achieve these functions. Since you where new to WPF, have brief knowledge about the WPF Panels. Also if you would like to stick with the existing layout and you need to expand the layout proportionally make use of ViewBox in WPF.
There is no simple answer to this. The WPF composition does a lot of hard work for you, if you let it.
If I can help it, I do not specify Width's and Height's but I would be lying if I said that I never do. In some data entry applications, there is no choice but where I do have a choice, I will let the WPF composition system do the work for me. Margins are the only layout property that will always get a look-in.
The WPF Composition system
The WPF Composition system will pass over your logical tree twice, once to measure the elements and once to arrange the elements based on the collected information. Some elements, such as panels, will attempt to take up as much space as they can. Some elements will attempt to constrict their contents as much as possible. Some elements will take up only the space they need.
An example is if you put a TextBox in a Grid without specifying Width's and Height's, the TextBox will take up the entire 'content' area of the Grid. If you do the same with a TextBox and a StackPanel, the StackPanel will constrain the TextBox to the MinHeight of the TextBox. Put a CheckBox in the Grid and it will take up only the area it needs.
Conclusion
There is no simple way to learn this other than to play.
I recommend reading the following links
WPF Architecture
Trees in WPF
They are both long reads but worth while. They will give you the theory you need to search for more practical applications of WPF and there are a lot of good blog entries out there that cover this topic.
In a ListBox derived CustomControl I need to draw lines joining ListBoxItems that are layed out in a Canvas ItemsPanel.
I can achieve this by having class ListBoxLines : UIElement that does drawing in OnRender and then including that object in my ListBox ControlTemplate (but to do that I need to pipe the listbox contents to that class...)
<ControlTemplate TargetType="{x:Type p:NetworkVisualization}">
<Grid>
<p:ListBoxLines/>
<ItemsPresenter/>
</Grid>
</ControlTemplate>
Im just wondering if there is an easer way. Id really just like to add my draw code directly to my ListBox derived class but if I do that it seems to draw UNDER the listbox canvas white background.
Is there any way to to custom listbox drawing directly in my derived listbox class?
EDIT: The motivation for this question is a custom control to display nodes and linkstrengths of a wireless mesh network as in the image below:
EDIT: Additional issue: The OnRender code for ListBoxLines (the node links) is cached - how to force a redraw of this when a node is dragging? Ideally i want to build the cache with the all lines except for the currently dragging nodes lines and only redraw while dragging the lines to that node - not sure how to go about that.
Thanks for updating the question - from the original description we were on completely different pages.
Personally I would not implement a control like this, as I know from prior experience that it is not easy task. In the last two three occasions where I have needed charting I have used middle-ware solutions.
The argument for middleware is an easy case to make:
It will save you significant development time.
You will get results quicker, allowing you focus on your specific requirements.
Even if you choose a commercial provider, the time saved equates to money.
I recently evaluated charting middleware options for a project less than 5 months ago so I can tell your directly that for a WPF application the best libraries are:
Mindscape Diagrams 2 (Commercial)
Chart# (Codeplex Project, Microsoft Public License)
I have used both products for studio applications (internal, however released as if the users were clients).
...
Take a look at the above solutions, come back with further questions (if any) and then if you still want to write your own I will at the very least point you in the direction and resources to do.
A side note, you say that you like the selection part of the ListBox - did you know that the selection functionality is actually supplied by the Selector base class?
I am new to WPF environment and I am experiencing some problems like if there are alots of things how do we manage them.for example I have three borders each of same size same location and they contains controls like textboxes etc etc we construct them sequentially but when it comes to edit we get in trouble modifying the border that is at bottom.
So in short how do we manage many controls on single page so that it remains easy to edit
Not sure I completely understand your concerns, but here are several point that make editing WPF UI pretty easy:
Correct usage of layout panels. If you will use approach with absolute positions for each control then it might become a nightmare to move or resize some of your controls. Correct layout (and panels such as DockPanel/StackPanel/etc) might help you a lot.
Incapsulating repeatable parts. WPF has a lot of feature to avoid repeating UI code. I'm talking mostly about Styles and Control templates at the moment. If you have your borders repeating through the entire window, maybe you should think on extracting this border as a ControlTemplate for ContentControl for example?
but I've found that encapsulating controls such as borders, textboxes etc in User Controls helps to keep things well managed (not to mention helps reduce code), similarly using a Resource Dictionary to store styles/animations is useful for very big projects (remember though that the local resources will take precedence when applied so remove them if they not in use)
furthermore, using Layout Panels such as Stacks,Grids and Dockpanels allows you to collapse User Controls when not needed or otherwise (also I've found that for some reason, Grids allow controls to overlap (when items are not correctly ordered in Grid Rows and Columns) which can lead to some elements not being seen in design.
Plan your layout properly and think through which Panels would be best for them, having to go back much later and change can be annoying (though admittedly it happens).
Also remember to use partial classes to properly structure your stuff, having to read through 1000+ lines of code to find something can be a nightmare.
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.