I am just beginning to learn WPF with the MVVM Pattern.
At the moment I'm stuck on a problem where I want to graphically visualize my current Model object by drawing a shape with dimensions databound to the VM's current instance of my Model. (It should redraw itself when a property changes etc)
This is what I've achieved (almost how I want it to look..):
My current approach is to derive a class from the Shape class with some dependencyproperties databound to the Models properties. This worked just fine until I wanted to have different strokethicknesses etc for different parts of the shape.
What I've tried is separating the drawing into two custom shape objects (that will be enough for my flexibility demands at the moment), but the problem right now is that they will not align correctly and scale differently.
This is how it scales/aligns with two different custom shape objects:
I'm thinking that there is probably way more efficient and flexible ways to tackle this. Do you guys have any ideas?
Thanks
Related
I am writing a new WPF control to draw and edit lots of shapes, say hundreds of thousands. To do so, I want to let the user define DataTemplate for his data. But LoadContent of this specific DataTemplate must return of specific type, IShape. How can I achieve this?
First, the whole point of templates is to support plugging in arbitrary visual trees. If you have a strict requirement about the composition of a template, then using templates was the wrong design choice.
Second, templates must describe a Visual. If you're going to be drawing hundreds of thousands of shapes, you will not be able to represent them as visuals. Visuals are quite heavy-weight
They participate in input hit-testing. (!)
They have all the overhead of Dependency Objects.
They participate in the inheritance context.
They must communicate property changes to their parent, i.e., for properties that affect layout and render.
They may contain dynamic resource references, for which they must observe changes.
They may extend the even heavier UIElement or yet even heavier FrameworkElement, which would mean:
They participate in layout. (!)
Routed events get passed through them, and may be handled by them.
They may be using data binding.
As an alternative, I suggest you provide an interface by which you can be fed geometry data, which you can freeze, share, reuse, and render efficiently. This will allow you to stick with the lowest-level set of graphics APIs available in WPF. But, honestly, even that may not be good enough.
One thing's for sure, though: presenting all these shapes in the Visual Layer is out of the question. I would, at minimum, implement some form of virtualization where you can efficiently locate only those shapes that are in view (quadtree or similar?), render only the geometry in view (with clipping), and use Cached Composition to avoid constantly redrawing; re-tessellating; and performing per-primitive antialiasing on the geometry if nothing has actually changed.
The LoadContent method of a DataTemplate returns the root element of the content of the template. So it will only return an IShape if the user (consumer) has acually defined an IShape as the root element in the template.
But you can't really force the consumer of your class to set a property of type DataTemplate to a DataTemplate that is guaranteed to include an IShape. The consumer might as well set the property to a DataTemplate that contains only, let's say, a Button.
What you can do is to throw an InvalidOperationException, at runtime, in your class if the LoadContent method returns anything else than an IShape. You can't make any guarantees at compile-time though. But this is how DataTemplates work.
Maybe you should consider letting the user set an IShape property instead of a DataTemplate property. You can let IShape (or Shape) be some kind of ContentControl or UserControl.
After all, a DataTemplate is a template that may contain any UIElement.
I've to draw a graph on a canvas (bound by a scrollviewer). And there are about 200 or so nodes in memory.
To keep the things simple, I have derived the nodes from a usercontrol which can render itself.
But I've not created the lines between the nodes. I know from MSDN that,
On the surface, the Geometry class and the Shape class are quite similar. Both are used in the rendering of 2D graphics and both have similar concrete classes which derive from them, for example, EllipseGeometry and Ellipse. However, there are important differences between these two sets of classes. For one, the Geometry class lacks some of the functionality of the Shape class, such as the ability to draw itself.
Because there can be lot many more nodes, the system may render things slowly. Hence, to increase performance, I feel the best choice would be Geometry (custom rendering).
My questions:
Should I go with Shape or Geometry to draw the lines?
Should I render only the current viewport area of the scrollviewer to speed up the display (in which case I would have to convert the nodes from controls to geometry objects), or should I just iterate over ALL the nodes and draw lines between them?
Should I render the graph in memory on a bitmap and then flip it? It sounds more like game programming that general application programming! :D
Doesn't WPF automatically takes care of rendering what's in view and what not for better performance?
A few points to ponder...
From your topic I get that you dont want the ability of nodes to redraw themselves as that may make them slower. Instead, you want to decide when and which node to draw. Am I correct?
Well that looks ok to me, however Canvas is never virtualized. I recommend going through the codeplex website and download the WPFToolkit source code. Under DataVisualization namespace you have several charting controls (even ScatterredChart which is similar to yours where lines are not drawn between nodes) and their source code. Observe what they have done. How have they increased performance of their graph tools.
I also came across this artical of how to implement a Scrollable Virtualized Canvas. Probably that can help you to achieve fast rendering of nodes over canvas.
Personally...
1] Geometries are lightweight and I like them.
2] Visual HitTesting can help you understand if an item is under rendered region i.e. within the bounds of the scroll view. Otherwise make it hidden so that it doesn draw itself. "Hidden" and not "Collapsed" because hueristic for scrolling would work fine.
3] I remember my colleague using even the virtualizing stackpanel with horizontal orientation so that it renders nodes and the unit view i.e. the region specific to one point on X axis so that such repeating regions would automatially fit together to produce a monolithic graph.
Wonderful that impelemntation was!
All the best and keep us posted of your progress on this.
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
I don't know if this is the best way, but what I am trying to do is to create a collection of Shape objects and then bind it to a Canvas, then whenever I update these Shapes, or add new Shapes (rare), the Shape objects on the Canvas will update as well.
Btw the Shape objects are not all the same, some Lines, Rectangles, etc. Not sure if that matters.
What's the best way to do this?
If you look at the question Is it possible to bind a Canvas's Children property in XAML? and further down there is an answer from Ivan which uses an attached property you can bind to and it automatically updates the canvas children. I haven't tried it but looks like it should work. Seems the best solution to me. The other option is to use the ItemsControl with a DataTemplate for each type you want to show - however that seems a bit fiddly.
I have been using WinForms since the first framework introduced and invested a lot of time and effort in it. Now I am attempting to move to WPF and, honestly, it's not so easy.
Now I have a task, I need to implement a simple wizard, each page of which has a aligned to center group of controls. The group contains a set of buttons, four button in a row. Width of the group is constant, height is variable -- it depends on the number of buttons inside.
It's a simple task for WinForms, but I have no idea how to do it using XAML.
I have three questions:
1). Obviously, the buttons inside a group is a WrapPanel which is placed in a Grid's cell. It's simple. But how to calculate height of the WrapPanel not using code behind?
2). Which is recommended way to implement wizard? Data template or some kind of Tab Control? I probably will need to have some transition effects when switching pages.
3). Is it acceptable in WPF world to use binding as a way to repositioning controls?
Thank you in advance!
The WrapPanel will auto-adjust its height based on its contents by default. WPF is a big advancement from WinForms precisely because of the new layout paradigms. No code behind is needed for anything you've mentioned.
As for 2; there are a lot of ways to implement this, depending on how close you adhere to MVVM (if at all); I'd recommend using a styled TabControl at first (you can adjust the style to present visually the steps in the wizard as tabs, without letting the user jump between tabs), as it's easiest. Also, it's possible to bind pretty much everything to the TabControl.
3 is possible, but should be rarely needed. And I mean it.
Now then; a simple example to show you the power of WPF.
You can have in your ViewModel (if you're not familiar with MVVM google it or read any of Josh Smith's articles or book or... wow there's such a wealth of information on it I don't know which to choose) a collection of objects, let's say Step classes, which you can bind to the ItemsSource of the TabControl. The TabControl will automatically create a tab for each of your Step.
Inside your Step class, you can have a collection of items, let's say... um, Collection<Push> (I'm struggling not to use known classes like Action or Button). If the ItemTemplate of the TabControl contains anything that recognizes that collection, as in a ListBox styled internally to use a WrapPanel for its ItemsContainer, you're done: the template will show the list of Pushes in a WrapPanel and that's that.
Now, I probably shouldn't write a full tutorial here anyway, but that should get you started. Read up on DataTemplates, ItemsControl etc. (again, I'm having difficulties picking resources... Dr. WPF has awesome articles on both, but they might be a bit advanced) and you should be good to go. Just remember that there's a good reason why WPF features a lot more fluid layouts than any previous desktop technology, you should become familiar with that.