4

I'm currently working on an C# WPF application that allows you to create a graph (i.e. a bunch of vertices that are connected via edges) and then use this graph as a pattern to find it in a bunch of other (larger) graphs ("host" graphs). Each graph element has at least a type and a label.

The pattern graph elements (edges and vertices) can have different "restriction types".

A vertex for example can have the restrictions "This vertex' label must be 'Vertex A'" or "This vertex' type must be in the set {Type A, Type B, Type H}".

For edges, the restriction types are a bit more difficult. An edge can be restricted to either be a "simple" edge or a "path" edge. A path edge between two vertices in a pattern graph can be considered a placeholder that allows you to find multiple edges (and vertices) between the two vertices in a host graph. In contrast, a simple edge allows you to find only one edge (and no additional vertices) in a host graph.

If an edge has a path restriction (instead of a normal edge restriction) it has some additional properties like minimum path length or allowed vertex types that are allowed on the path.

The type restriction structure can be seen in this UML class diagram: image1

~~~

Now from the UI point of view: A user should be able to configure if a edge has a path restriction. If it has, the neccessary additional controls (TextBoxes, ListBoxes etc.) for the additional settings should automatically appear. Changes in all controls should automatically be reflected in the data structure.

Here's what the user interface should behave like when changing settings of a selected edge: image2 (Actually, on the right side there should also be a scroll bar on the right side that allows you to scroll down and configure also the allowed edge types on the path. Also ignore the vertex and edge overlap settings for now.)

~~~

Finally, my questions boil down to:

How do you implement such a dynamic object class change while maintaining WPF's data binding elegancy? (With dynamic object class change I mean that by clicking on the "Consider this edge as a path" checkbox the selected edge will get a different restriction type.)

Do I really have to create an old-school event listener that gets triggered when changing the value of the "Consider this edge as a path" checkbox and use it to update the visibility of the other sidebar controls "manually"?

Would it help in any way if I changed my restriction class structure somehow?

Hauke P.
  • 2,695
  • 1
  • 20
  • 43
  • 1
    http://en.wikipedia.org/wiki/State_pattern – Yam Marcovic May 28 '13 at 12:32
  • You may want to have a look at [my Nodes Editor Sample](http://stackoverflow.com/a/15580293/643085). All you're discussing here is already implemented in the sample and in a really elegant and clean pattern (MVVM). – Federico Berasategui May 28 '13 at 13:58
  • @HighCore: Thank you for your nice example. However, the example does not deal with "changing" an object's class as required in my case. – Hauke P. May 28 '13 at 14:20
  • @HaukeP What do you mean by "changing an object's class"? that doesn't make sense. You can't even do that with standard C# objects. If you mean "changing an object's properties", then you can perfectly do that by adding the relevant code to the ViewModels. Also, if you need to "swap" some objects for others, that can also be performed at the ViewModel level. – Federico Berasategui May 28 '13 at 14:26
  • UI is not data, and your statement about `old-school event listener` is completely against everything WPF stands for. Also, please don't use java terminology, it makes me vomit. – Federico Berasategui May 28 '13 at 14:27
  • Yes, I know that you can't "change" an object's class - you have to replace it somehow with another object. I just didn't find a better way to describe what I'm trying to do - that's why I put it in quotes. What I'm still trying to understand about the MVVM concept is how the VievModel itself can change (i.e. properties are added or removed) when changing the underlying Model. To take my example: When checking the "Consider this edge as a path" box, both the View and the Model have to change. Doesn't the ViewModel have to as well? – Hauke P. May 28 '13 at 14:47
  • 1
    @HaukeP. your VM should remain the same, and you can change the Model `within` it, say VM has a `public Model Model` property, then you change that from `ModelA` to `ModelB`. Then the relevant parts of the UI are based on `ContentPresenters` which render the appropiate `DataTemplate` for each model type. Pretty much like I`m doing in my Nodes Editor to show different editors in the left panel for Nodes and Connectors. Check it out. – Federico Berasategui May 28 '13 at 14:56

2 Answers2

3

Okay, I don't really speak design patterns, so I'm not answering in those terms. I do speak WPF though, and design patterns usually turn out to be something I'd already done but didn't know what it was called.

WPF doesn't really care what type anything is. If you're displaying it using a DataTemplate in a ContentControl of some sort you can have one for every type the object might actually be that needs special treatment and WPF will take care of that for you. A DataTemplateSelector might be a good idea for more complicated logic for choosing the UI pieces for a given type, which in my experience tends to happen in many supposedly simple scenarios that turn out not to be. The disadvantage is that a DataTemplateSelector has to know about all your data types and templates in order to be able to choose between them.

This only really works for the side panel though, the rendering of the actual graph probably needs to be done in a more holistic manner and is, I would say, a completely different problem.

Matthew Walton
  • 9,809
  • 3
  • 27
  • 36
  • Thanks a lot for the first answer. After some more searching, I found [this answer](http://stackoverflow.com/a/5326097/1560865) which seems to be similar to what you suggested. Both answers help a lot with controlling the "visibility" of the neccessary controls. But how would you implement the CheckBox "_Consider this edge as a path_" that has to actually change the **type** (i.e. the class) of the restriction? – Hauke P. May 28 '13 at 13:20
  • To put it more precisely: To what kind of binding source would you bind the IsChecked property of the "_Consider this edge as a path_" CheckBox? To be honest, I'm not that much into WPF bindings - would a converter help here? Or would that be a completely wrong choice? – Hauke P. May 28 '13 at 13:29
  • It's a bit awkward, but you could bind it to a property of a parent object of the edge, which in its setter triggers the appropriate code to swap the edge out for a path. The alternative involves handling events on the checkbox in the view, and using those to call viewmodel methods which perform the swap. Your preference, really. – Matthew Walton May 29 '13 at 09:41
3

The design pattern you're after is probably MVVM. It looks like you're currently attaching your UI to your model directly with no view model in between. Sometimes you can get away with this, sometimes not.

You could write a value converter applied to the binding of the IsChecked property that converts a boolean into the correct instance of a restriction class and back. As the checkbox state changes, a different instance is created and assigned into your model. This will be reflected in the UI with the choice of data template.

It's likely to be more complicated than that, for example if you want to preserve values between the changes of state. That is where you would want to introduce a view model to sit in between the UI and the model. The view model closely reflects the UI and has a corresponding boolean property, and when that changes you can change the model accordingly.

Either way, there should be no reason to hook onto events on controls: try and handle this all in view models.

Tim Rogers
  • 21,297
  • 6
  • 52
  • 68
  • That sounds very helpful. Still some questions remain: Should I create only one ViewModel that contains all theoretically possible properties and additional properties responsible for the visibility of controls? Or should I create two ViewModels, one for vertices and one for edges? Or even three, one for vertices, one for simple edges and one for normal edges? – Hauke P. May 28 '13 at 14:38
  • You probably want one overall view model for the edge representing the common parts of the UI. This will contain one of either two view models representing the different UIs that appear when changing the checkbox. Create two DataTemplates for showing each of these. – Tim Rogers May 28 '13 at 14:50