I am new to C# and WPF and I need to create a diagramming control similar to MS Visio but without direct user interaction. I have tree-like hierarchical data whose nodes can be of the same type. Quite like graphs whose vertices themselves contain graphs (i.e. vertices are subgraphs). I cannot use the Graph# library for several reasons.
The main requirements for my (customized) control are:
free moveable/draggable items (which represent hierarchical data)
items should have a box layout
items can be connected by arrows
Unfortunately, I don't know how to start. I tried several approaches like nesting ListBoxes but each approach had disadvantages. What do you think about nesting TreeViews and templating them? I need something like a Canvas container to freely position my items.
Do you have any suggestions? Thank you very much in advance.
If you need free movable/draggable items you probably need a degree of flexibility that built-in controls don't really provide. You're better off constructing your own controls, perhaps deriving from existing controls that provide close-enough functionality.
So for starters you'd have a control for a box item and a control for an arrow. The controls need to be movable and draggable inside a container, so you'll also need a container, probably derived from Canvas.
What I'd really recommend is to have a look at Model-View-ViewModel techniques; they can be daunting for a beginner but the benefits are immense. In this case, you'd have a collection of objects that represent your structure; all the objects will have, for starters, X and Y properties that define their coordinates. The objects are represented on the page by the previously mentioned controls, with bindings from their relevant properties to the properties of the objects. The objects are the ViewModel, and the controls represent the View.
Then, when you move the items with the mouse (the code for that is pretty easy), the properties of both the controls and the objects are automatically updated. More properties for the objects can include size, labels, and a collection of snap points that represent where arrows can connect to the object.
Arrows can be represented with the same concepts, except that instead of explicit X and Y coordinates they would have associated objects and snap points; then their coordinates would be automatically calculated based on the positions of the snap points.
Based on these structures, you can do actions exclusively from the ViewModel, like adding new items automatically connected to their parents, and have the view update based on that.
This is quite a broad topic so I really should stop now; I don't even what articles to recommend to get you started. Probably anything by Josh Smith on the topic of MVVM :P
Related
Not sure if I'm going about this the wrong way, but I have an application where a user creates various cuboid objects of different dimensions and positions. These objects are displayed in a Viewport3D and the user can add/edit/delete them and can move the object by doing a drag/drop which should update the underlying data. The cuboids are defined relative to some base coordinate system (meaning that I have nested cuboids where the local coordinates are relative to some parent object). The data itself needs to be persisted for later re-use. I'm currently storing the data in an observable collection that I serialize. However, what I'm not sure is how to dynamically create a ModelVisual3D and have it be bound to a list object that contains a MatrixTransform3D which defines those properties. A DataTemplate does not appear to be usable on a ModelVisual3D or the Children because it is a VisualCollection and not an ItemsControl object. I'm not sure if I'm thinking of this the wrong way and if so, any suggestions would be appreciated. Can this be done in XAML or is this all code-behind? I've seen a possible code-behind solution, but is there a way to take advantage of letting the XAML do it? --> How can I use databinding for 3D elements like Visual3D or UIElement3D
What I want to create is a list view that will resize itself in order to show all items. Normally I would use AutoSize, but this won't work here. Any other options how can I make ListView expand and shrink to fit all?
You will have to manually calculate your desired height and set it as items are added/removed.
Detecting item addition or removal isn't directly supported - so you'll either need to create your own Add/Remove Item calls for clients to call, or handle LVN_INSERTIEM type messages from WndProc.
Auto-sizing controls are usually trickier to use - as you have to track Min/Max sizes, allow room on the owner, and usually add to an awkward usability point for users. Only do something like this if typical solutions (i.e. scroll bars) truly can't work for your need.
"AutoSize" property is not supported for the "ListView" control. As #JohnArien mentioned, you will have to programmatically re-size your list view control's size according to the number of items available. But be warned that this may not be a good idea in terms of visual appeal of the Form. Your form design might look ugly if you change the size in run time. More over these types of controls are expected to expand their client area within the given size with the help of scroll bars. I would strongly suggest you to reconsider this option.
First of all, here's some concept art for how this custom list control must look:
http://img816.imageshack.us/img816/1088/customlistctrl.png
Each list item is fairly complex and turns into an "edit interface" when the mouse hovers over it. I also have PNG image files for every skinning detail of this thing, including the scroll bar.
What is the best approach to get started implementing this? Would I create a custom control and simply render all of this in GDI?
Could I make the list control a transparent clip region with a scroll bar? For the individual list items, would I simply use a textured panel as the backdrop for each item and place existing .NET forms (like combo boxes, buttons, edit fields, etc) as children of that?
I've never had to create something this detailed before.
If you want your control to look exactly like the given picture (which is nice), you will end up drawing much of it, if not all of it, yourself. One possibility is to subclass each control being used and override the OnPaint method to do your custom drawing. This assumes a design where everything in your picture is an individual control.
I myself might make each row a separate UserControl-derived class, perhaps with an internal constructor so users of your control can't create the row directly. Within your SkinnedListRow class (or whatever name), you could have each of the subcontrols. By the looks of things, the row contains three controls that display numbers and one that displays any kind of text.
For the editing portion, derive another UserControl that contains all the controls you picture. Both the display controls and the editing control are owned by the SkinnedListRow from above, so it knows how to load data from one set into another.
You have a good amount of work in front of you, but your idea looks nice. Good luck.
As my first WPF project, I am attempting to build an application to play a card game similar to Magic the Gathering. It is not clear to me how to lay out the main play area. You can see some examples that are similar to what I am attempting by looking at example 1 or example 2. The chat/info areas on the right would be separate user controls.
The cards must maintain their aspect ratios, and each play area would start with 10 columns and two rows of cards. As more cards are played, the number of columns and/or rows may change. Each player area may have a different number of columns and/or rows. Cards may overlap, and may be placed sideways (tapped). Cards in all areas should be the same size (although they may be cropped in some areas). Cards do not need to lie exactly on the grid (they do not necessarily snap-to-grid).
When the user hovers the mouse over a card, it should expand to a significantly larger size using an animation. A card in one player area may overflow into the other player's area when expanded (but only as long as the mouse hovers).
Given these requirements, I am tempted to use one large user control derived from Canvas with image objects for each card (along with other shapes to delineate the areas). This implies that I will be doing a lot of work during the OnRenderSizeChanged event to position the child items within the canvas (manual layout).
Using a grid does not seem feasible to me, due to the free-form placement and overlap.
Decomposing the play area into smaller user controls would leverage the WPF layout capabilities, but it seems like decomposition would prevent the cards from expanding into adjacent user controls during the mouse-over, so that doesn't seem feasible either.
Is there a better alternative to one large canvas-based control? It seems wrong to be doing manual layout in WPF, but I cannot see an alternative.
This sounds like a great scenario for Composite Application ala Prism. It provides solid framework for implementing regions, modules, sending message between modules etc... From looking at your screen captures, developing a shell with different regions and dropping modules into them would probably greatly benefit your layout. As for the cards themselves, perhaps they could be modules as well?
Check out:
http://msdn.microsoft.com/en-us/library/ff649780.aspx
Particualy good examples come with the download package including a stock market like application and event aggregator example.
You said:
Decomposing the play area into smaller user controls would leverage the WPF layout capabilities, but it seems like decomposition would prevent the cards from expanding into adjacent user controls during the mouse-over, so that doesn't seem feasible either.
But this is not correct. Decomposition is absolutely the right approach to take, and this would not prevent the cards from expanding into adjacent user controls. The reason being that you can use a RenderTransform rather than a LayoutTransform. See this example, by Charles Petzold, or this article, to visualize the difference. Because a RenderTransform is applied after the layout has already occurred, your cards would be able to expand outside their bounds.
Given that decomposition is the right approach, I would arrange your various card collections into a Grid, with each collection being an ItemsControl. The ItemsControl should bind its ItemsSource property to some collection, and then you can provide a custom ItemTemplate that would display the image and any other information. I would be hesitant to use a Canvas, as this would restrict you to hard-coding the positions for the cards (which is a very WinForms-like solution for a problem that can be far more elegantly solved). Take advantage of WPF's fantastic layout engine and use nested grids and items controls to create a dynamic layout. This will ensure that your game board looks good at any resolution and when stretched to various sizes.
I recommend you take a look at this guys project . In java I know but if I was to go the route of building a card game. That would be what I would go off of.
A lot of canvases inside of a grid could help you here, the canvas will allow the content to render outside of its bounds, as long as you turn ClipToBounds to false, and you will be given much more control over exact placement of the cards than with other schemes. You will also get the powerful functionality of a grid control, allowing you to add and remove columns and rows as needed (though you will also have to dynamically add and remove canvasses, though this isn't too difficult.
If you're worried about the contents of your "Card" moving around when the box is rescaled, surround it in a viewbox. It will manage all your scaling for you, and ensures your card uses as much real estate as it can get. Alternatively you could use a RenderTransform, but a lot of these might slow your program down (Experts: does the viewbox operate using RenderTransforms? If so this point is moot)
To ensure the cards maintain their aspect ratios make sure each Image's Stretch attribute is set to "Uniform", making them all keep the same size could be done by designating a master card, and binding heights and widths of all subsequent cards to this original card, though that is a little messy and doesn't allow the cards to expand. Another solution is to set a single size for each card manually, animating this when you want to expand or shrink.
I have a data model that represents segments of a curve that looks like this:
Envelope curve http://img710.imageshack.us/img710/9059/envelope.png
The fields are x and y coordinates of the anchor points (red), and a slope value represented by the control points (green). For the curve to be editable by the user, I'm thinking of using Thumb objects for both anchor and control points.
Since I also would like to be able to present the user with an interface where it is possible to enter coordinates into text boxes, I'm thinking of implementing this curve editor as a lookless control. The problem I face is to find the best way to organise the elements. Some thoughts on what I could do:
Add the data model view objects to an ItemsContainer with a custom ItemsPanel and a DataTemplate that creates one anchor point and one control point for each data model object. This causes two and two points to be wrapped in a ContentPresenter which makes the interaction between the custom panel and the thumb points difficult.
Use two different data model view objects, one for anchor points and one for control points, and a DataTemplateSelector to select the right DataTemplate. While there still is a ContentPresenter between the item and the panel (is it possible to avoid this?), interaction may be easier when there is only one item in the ContentPresenter.
Don't use ItemsContainer at all, instead add the Thumb objects directly to the visual and logical trees of the custom panel. Of course I loose a lot of flexibility when it comes to the look and feel of the Thumb objects when they are not specified by templates. Maybe it's possible to duplicate this functionality from ItemsContainer so my control can have separate DataTemplates for the anchor and control points. The Thumb objects could then be added directly to the panel without ContentPresenters.
What's the most reasonable way to do this? Are there other alternatives than the ones I've thought of?