views:

487

answers:

4

I currently need to create a visual representation of a ferry system that displays the actual ferries their position on the sea and the state of their cargo. The ferries contain trucks and the trucks contain cars. I need to display the actual trucks and their xy postion on the deck. When the ferries are loaded the postions of the trucks are updated frequently so the look animated. Also I need to display the actual cars on the trucks. Trucks, cars and ferries have some states that need to be displayed too. So I have a hierarchical structure of data that I need to visualize in a rather realistic manner.

What would be a good way to implement this kind of stuff in WPF? Should I use MVVM with one TreeView control and create a HierarchicalDataTemplates for sea, ferry, truck and car and a ControlTemplate for the TreeView? Or should I better use UserControls and compose and update them in code instead of databinding to observable collections of the ViewModel. Do you have any experience with this? How would you do this? Could you sketch out class/control setup?

A: 

WPF works really really well with view models. If you can keep code behind away until specifically needed then you can separate ui from data so much more easily. It will allow your ui's to be some much more upgradeable if the data model doesn't change between different display.

Preet Sangha
How would you do this? Could you very briefly sketch out class desgin /control setup?
bitbonk
+1  A: 

I'd suggest having one user control handle all the drawing. Otherwise you can get lost the the hierarchy of objects. Also it makes it easier if another item was added, say people in cars, trucks and ferries.

If your model is hierarchical then you can just pass in the top level into the control, and let the control sort itself out.

MVVM works well for existing controls, but existing WPF controls only work if there's a control that's close to what you need, and with a few tweaks would work. I can't think of a standard control in WPF that's close to what you need, so it's time to write a new control.

Cameron MacFarland
I have thought about this too. The hardest part here I can not yet really wrap my head around is how to build the databinding (be it the builtin WPF databinding or some custom mechanism) that binds the herarchical data to the one user control.
bitbonk
Yeah binding doesn't work in this case. WPF controls and bindings are designed for simple controls with simple bindings. For a complex control like this I'd just bind the root item to the control, and then let the control handle updating internally.
Cameron MacFarland
+4  A: 

I'd recommend making a "lookless" control as opposed to making user controls. Generally I use user controls as glue/container for my lookless controls. An example of a lookless control is the Button class. It contains a default style and in Blend, you can modify the style all you like. It also supports the visual state manager so you can change how the presentation looks when states change. You can think of the codebehind of a lookless control as a mini ViewModel. Here it is ok to mix some presentation stuff and your domain classes.

If you follow this same design, you could create a Ferry lookless control. This control would have a set of it's own dependency properties (possibly listening to the OnChange of the DP).

Your Ferry control may have an ObservableCollection DP called "Trucks".

Then in your Themes\generic.xaml, create a default style for your Ferry control. Your default style may have an ItemsControl with an ItemsSource={TemplateBinding Trucks}. The ItemsControl panel template, could be your own custom panel for arranging the Trucks, or maybe you use a Canvas. For the ItemsControl items template, you would have something like this:

<DataTemplate>
     <mynamespace:TruckControl/>
</DataTemplate>

You Truck control, would also be a lookless control with it's own default style, and it's data context will already be set, so you can directly do the {Binding Path=xyz}. Your Truck control could also set it's Canvas.Left/Top (if you chose to use a canvas in the pervious items control..or maybe it doesn't set its position at all if you made a custom panel for it) or a render transform as to put it at the correct X,Y. You could also use the items control in the truck's template to render out the cars in the same fashion you rendered out the trucks in the ferry control. Also its possible to create states for the VisualStateManager as to make it fully Blend supportable. So if a truck goes into a "problem state" you could easily style that state in blend to make it blink red, for instance.

I know it sounds like a lot to digest, but in the end having stylable controls all supporting an MVVM model will make your life 1000000x easier.

I'd suggest studying Microsoft's silverlight toolkit to get a good idea how to do lookless controls and such. Try looking at a simple control, like the DatePicker ( http://silverlight.codeplex.com/SourceControl/changeset/view/25992# ) One caveat is ignore DatePicker.xaml file (it's just a mirror of what gets put in generic.xaml and nothing bad would happen if you just deleted it).

The things you should pay close attention to are:

1.) The attributes on the class. These help Blend know how to deal with your control.

2.) The OnApplyTemplate override. This is where you can pull out specific elements from your template. These are known as "parts" and you will see the parts tab in Blend. The attributes in #1 can define what "parts" are in the template and what type they are expected to be.

3.) The DefaultStyleKey = typeof(...) in the constructor. This tells Silverlight what default template to use in the generic.xaml

4.) Look at Themes\generic.xaml. This is a special hardcoded file location that stores all your default templates. Search for the DatePicker style and you will get the idea :)

Good luck!

Jeremiah Morrill
What a awsome answer thanks alot. It makes perfect sense. I will not mark this as answer yet, I will start a bounty to award you with some more points :)
bitbonk
Thanks!A slight variation of this...you could also create your own ItemsControl subclass that is configured to automatically generate it's container. Here is a decent example http://silverlightcoverflow.codeplex.com. Note the author's disclaimer of it being their first ItemsControl...so take the code with a grain of salt for best practices ;)
Jeremiah Morrill
One more thing: Do you think it would be at all possible to achive this using just the TreeView conrol and writing datatemplates for car,truck and ferry and maybe a control template for the TreeView? In my example the TreeViewItems in the tree behave differently but in a treeview it seems that all items behvae the same (e.g. they all have the [+]/[-] expander) I just can adjust what is contained in the item using a DataTemplate. But in control template I can not differentiate between cars trucks and ferries. Is this correct?
bitbonk
A TreeView certainly would work as long as you think the behavior and stylabliliy of the TreeView is enough for the desired result. With SL, you don't have implicit (typed) DataTemplates, so you can't automatically have your template be selected based on your model's type. But the TreeView can use the HierarchicalDataTemplate, so you can have different model types per node level. For example, all root nodes have to be model-a. All root nodes level-1 need to be model-b.
Jeremiah Morrill
+1  A: 

I just wanted to let you know, how I actually implemented it. It turned out that it was not necessary at all, to write custom controls or UserControls for this. All I did, was writing datatemplates for the car, ship, ferry, truck etc ViewModels. For example the datatemplate for the FerryViewModel contained an ItemsControl with a ItemsPanel of type Canvas (to be able to position the trucks) and an ItemTemplate that was a DataTemplate for TruckViewModel. A very simple and fast approach.

bitbonk