Consider a ViewModel that exposes a tree defined in the Model, which is then data-bound to a TreeView. The tree is rather large and the model is used directly because it is essentially read-only with regards to the view. Now, the TreeView lives under a TabControl in the VisualTree, so an issue at this point is that the IsExpanded and IsSelected properties aren't preserved when switching between tabs. One hesitates to add these boolean properties to each node in the Model, as this should be extended in the ViewModel as a matter of principle. The tree is composed of polymorphic nodes, so if we were to create a ViewModel node type that derives from the tree node types and adds these properties, it seems this would result in some hairy code in the ViewModel:
That is, if the tree has an abstract NodeBase, and then derived types Node1, Node1, ... NodeN (the Model's Nodes). The ViewModel then has to encapsulate these nodes, so when creating a ViewModelNode, if it has a reference to Node and also references to child ViewModelNode's for each descendent ViewModelNode that encapsulates each descendent Model's Node all the way down the tree, maintaining these child references in the ViewModel identically to how they are maintained in the Model, along with a reference to the Model. i.e. all references in the Model nodes are replicated in the ViewModel nodes, in order for each Model node to be encapsulated by a ViewModel node. The existence of redundant references such as this, even if handled in the ViewModelNode's constructor, just smells bad.
What is the most accepted means to extend each node in a tree in this scenario, without wholesale replication of the references as stated above? (And to a lesser point, is the mere mention of using the model directly by the view an unforgivable crime, or is this forgiven due to the circumstances?)
There is perhaps an argument to be made that implementing those Boolean properties on the Model is OK, but personally I would look to creating ViewModels for each Model that's going to be in the TreeView. One advantage of doing so would perhaps be an increase in scalability, should you ever decide to implement more functionality related to the TreeView.
I think it depends on how much you are actually doing with the TreeView (within your app), but I do think the more you're doing, the stronger the argument for a ViewModel-based solution.
With regards to the hairy code, you could perhaps circumvent this to a degree by using an interface to describe your TreeView members, e.g.:
public interface IMyTreeViewItem
{
bool TreeViewItemIsSelected { get; set; }
bool TreeViewItemIsExpanded { get; set; }
// Further potential properties
string TreeViewItemHeaderText { get; set; }
List<IMyTreeViewItem> TreeViewItemChildren { get; set; }
}
This approach can be used to ensure that your TreeView members are properly "subscribed". There's also then an option to reference the interface type in XAML, for example, as the TargetType of a HierarchicalDataTemplate for the TreeView.
Related
I have a recursive hierarchy of three kinds of object in a C# library. Let's call them Boxes, Nuts and Bolts. Boxes can contain other Boxes, or Nuts and Bolts. Nuts and Bolts obviously can't contain anything.
Let's assume each Box has ObservableCollections of Box, Nut, and Bolt. Each Nut and Bolt implements INotifyPropertyChanged.
Is there an accepted best practice for propagating notifications of changes to the observable collections, or property changes on any Nut or Bolt to an object which holds a reference to the topmost Box? Or any particular design patterns you would recommend?
EDIT: to give some background to this issue, I lead the Chemistry for Word project. You can see the component that display structures in real time on the left.
Now, believe it or not, this currently draws everything through data binding. Each of those molecule displays on the LHS is an ItemsControl. (And yes, I am using WPF with MVVM!) This has proven to have too many overheads and lack of flexibility for a long-term solution. So I have gone back to generating DrawingVisuals directly. This approach allows much more fine control.
The Boxes, Nuts and Bolts in my original example are Molecules, Atoms and Bonds. If any of these are added, removed or changed then the display has to know about it so it can update. As I have already implemented the interfaces and objects for data binding then I want to exploit the code I already have.
I've had a similar model with fast-path access to upstream Node instances in directed acyclic graphs. A Node has a weak reference to its immediate parent. Node has a property to get the Root...that tries to return its parent's Root. If there's no parent, then that node is a root. Rootness is based solely on containment. Note that the parent isn't a collection...because sometimes the child node isn't even in a collection. Something more-or-less like...
public abstract class Node
{
WeakReference<Node> parent;
public Node Root
{
get { return Parent?.Root ?? this; }
}
public Node Parent
{
get
{
if ( parent != null )
{
if ( parent.TryGetTarget( out Node parentNode ) )
{
return parentNode;
}
}
return this;
}
internal set { /*...*/ } //--> if you're brave...
}
}
Edit:
Regarding WeakReferences...one of the things our graphs can have is references to nodes in other graphs. We have a node resolver service that will fetch those other nodes. These out-looking references are represented by an identity value (a GUID or a Long) and an associated weak reference. This way, we can load the specified node as needed, but not keep it any longer than necessary. The resolver maintains an LRU cache of nodes resolved this way.
If such a resolved reference needs to resolve its own parent, a similar mechanism exists to allow the dependent node to resolve its parent. Even a node's collected child nodes may be lazy loaded via the resolver service (although there are annotations that inform our framework when to lazy-load and when not).
So, the weak references help with all these incidentally-resolved scenarios. Er...more accurately, they help us not screw up the garbage collection in such scenarios.
In some analytical scenarios, we'll have hundreds of thousands of nodes popping in and out. I could imagine similar dynamics in chemistry modeling.
Why don't you call the parent in the change notification. Something like the following pseudo code:
Bolt()
{
NotifyPropertyChanged(property)
{
PropertyChanged(this, property);
}
ChildNutPropertyChanged(Nut child, property)
{
PropertyChanged(this, child + property);
}
}
Nut(Bolt parentBolt)
{
parent = parentBolt;
NotifyPropertyChanged(property)
{
PropertyChanged(this, property);
parent.NotifyPropertyChanged(this, property);
}
}
If you encapsulate your ObservableCollection of Nuts and Bolts and only make a ReadOnlyObservableCollection public, you could make an Add(Nut nut) method (and another one for bolts) that registers to the added Nut's NotifyPropertyChanged event.
This way, you'll know in the Box when a property of a child has changed and take action.
I'm new to MVVM so I'm trying to figure out what is the best way to do this. I'm using WPF with Caliburn Micro for this.
I have two different views (each with their view models) for the model I'm trying to manipulate. One view shows the model in a tree view while the other shows a table view of the data.
My model basically looks something like the following
public class Foo
{
public string Name {get;set;}
public string[] Categories {get;set;}
}
The Views are different ways to visualize collections of Foo. The table view is pretty straightforward, but the tree-view will group Foo by the category it contains.
So if an instance of Foo is something like
var fo = new Foo(){Name="one",Categories=new[]{"a","b","c"}};
Then the treeview would be
a
|_ one
b
|_ one
c
|_ one
I have two questions about how to connect the model to the view model in the spirit of MVVM.
What is the best way to populate the viewmodels from the model for the different views? I was thinking something like a singleton FooManager that is accessed from the view models. Or would using the caliburns SimpleContainer be better suited for this?
Lets say I manipulate Foo in the table view by changing it's category collection. How would I propagate the change to the treeview, since that would mean that Foo would appear in a different tree node? Would Foo need to implement PropertyChangedBase' and somehow bubble up the changes to the other ViewModel? Or would it be better forFooManagerto implementPropertyChangedBase`. Seems like the latter would be more reasonable.
TIA
For collections that change reference BindableCollection and are presented on the view.
As for bringing data into a view you can do it through a combination of DI/IoC, via constructor injections on the ViewModel in question. Most of that is done thru Interfaces that can be found in the Container of your choosing either SimpleContainer to MEF if you prefer or what ever IOC/DI container you choose really, the framework is such that can be extended with any container. Going with Interfaces allows for mocking and unit testing of the viewmodels.
Yes bubbling of the change to the View is usually done through what you had though by means of implementing INotifyPropertyChange which is part of the PropertyChangedBase class object.
One thing that will probably rear its ugly head is that Collections based off ObservableCollection don't necessarily bubble the changes of the underlying item's properties in the collection, that is an entirely different thread on SO
This question is a follow-up of this older one, and it's more of a confirmation than an open question.
My ViewModel instance has a private instance of the Model, _modelInst.
The ViewModel has exclusive access to the Model's data during editing (so the Model doesn't need to implement INotifyPropertyChanged).
Now there are three ways I came up with how to edit the Model data from the View:
Getting/setting directly on the Model instance
e.g. for simple value fields
return _modelInst.fieldname;
_modelInst.fieldname = value;
This one's easy to implement...
Creating a ViewModel instance and operating on the parent's data structure
e.g. for more complex object types like structs:
Creating a new ViewModel for that type.
The ViewModel knows the parent and its fieldname.
displaying that in a ContentControl+DataTemplate
getting / setting:
via methods of the parent with the fieldname as parameter,
overwriting the whole original object even if only one field is changed
This means creating a new interface (with update routines working on _modelInst), implemented by the parent, for each of these structures.
Creating ViewModel instances with no direct knowledge of the parent's data structure
e.g. for (lists of) classes within parent classes
Creating a new ViewModel for each class
Sending update instructions to the parent via
commands
messages
reflection (parent knows which child called the function
by comparing the instance to all stored children)
All of these are a big mess implementing, creating functions for
every field of the model that is editable.
Which means pretty much all fields of the model...
(4.) One could create a generic ViewModel which works via reflection alone, where each
subobject knows its parent and its fieldname (+index, if in a list).
Only the root's logic would then interfere with the model.
But that solution would also require a means to store the path to a field within _modelInst.
Is there any other (more simple) way to achieve this?
Did I misunderstand the principles of MVVM (again)?
Is MVVM suited for manipulation of large hierarchical data structures?
Hopefully these resources will help; they helped me quite a bit as I learned MVVM and how to approach representing object graphs/hierarchies with view models:
Editable Object Adapter
Editable Collection Adapter
MicroModels
This is an excellent question for which I do not feel there is a good answer that comes stock with the MVC pattern.
ViewModels work great when the model they map to has no children.
But when the model has children, as in
Customer
-->Order
-->Country
(imagining Country were a child object of Customer) the design pattern kind of breaks down.
The best thing I've found is to use inheritance and selectively expose
only those children for which you need viewmodel logic. Otherwise, just access
the model's properties of the view that will come in via inheritance.
public class CustomerView : Customer //inherits from Customer (model)
{
public CustomerView(Customer customer)
{
this.FirstName = customer.FirstName
//etc..
//Only if you need it, that is if you have some display-specific
//logic relating to country for a given view, you create
//a CountryView class that inherits from Country and gets populated
//by an instance of it as well
this.CountryView = new CountryView(customer.Country)
}
public CountryView CountryView {get;set;} //sadly you cannot override Country but you may be able to shadow it.
public string DisplayColor
{
if(base.FirstName == "Joe")
{
return "red";
}
return "";
}
}
This gets messy when dealing with grandchildren. If anyone has a better solution, I would love to hear it.
Thanks
I have a hierarchical generic data structure. There is a root node and under that there can be many tree nodes, or just a single data node, and tree nodes can have more tree nodes. A basic tree structure.
All data in my system is persisted in this format. I do however want to have a strongly typed interface to some of the different types of data that these data structures represent (ie. turn a generic hierarchical tree into a strongly typed address record).
I was planning on using an adapter pattern where I pass in a node to the adapter and it then exposes properties by interrogating the tree. This would also allow me to validate the tree (ie. that is has specific elements and that they have valid data in them). It also allows for extensibility (ie. the tree itself would also be exposed if there were additional data that was added at a later date).
Do you think this is the most optimal approach to achieve this or is there a simpler way?
Note: this is in C# and .Net 4.0.
Thanks!
An Adapter is usually used to bridge between two incompatible interfaces. That doesn't seem to be your problem here. In fact, I don't really see any problem -- as object languages are by nature hierarchical, you should be able to use a mostly 1-to-1 mapping between a class and a tree node.
Perhaps by "Adapter" you just mean a class that wraps a Node or whatever particular Object type that describes your tree nodes, and I'd agree. There should be fairly obvious parent-child relationships that you can describe by having your node classes own or somehow return an array of child node/classes, and the attributes as getters/setters. Any needed validation could be done by the setters, or if need be during construction as a class inspects a given node and its child nodes. Something like the following:
public class NodeFu {
private Node node;
public NodeFu(Node node){
this.node = node;
// perhaps traverse and validate node data here
}
public String getNodeAttribute(String attrName){
// pardon the offense, Demeter, only for demonstration...
return node.getAttributes().getNamedItem(attrName).toString();
}
public void setNodeAttribute(String attrName, attrValue){
node.setAttributeValue(attrName, attrValue);
}
public ArrayList<NodeFu> getChildren(){
ArrayList<NodeFu> children = new ArrayList<NodeFu>();
for (Node childNode : node.getChildNodes()){
children.add(new NodeFu(childNode));
}
return children;
}
}
I'm assuming you have more business logic to add to this class that will manipulate the data on the Node itself, otherwise the Node class would suffice and you could just use it directly.
the best way to explain is with example so:
this is the model
public class Person
{
public int age;
public string name;
}
this is the view model
public class PersonVM
{
}
my question is:
should the vm expose the person to the data template or encapsulate the model properties with his own properties?
There is not a general agreement about that question. For example it was one of the open questions about MVVM formulated by Ward Bell here:
Is the VM allowed to offer the V an
unwrapped M-object (e.g., the raw
Employee) ? Or must the M-object’s
properties (if it is even permitted to
have properties!) be exposed
exclusively through the surface of a
VM wrapper?
The principal advantages of not directly exposing the Model in the VM are:
you can use it as a "converter on steroids", formating the model values in a convenient way for the view
you can inject other funcionality related to the user interface, like data validation messages, undo redo,..
The cons are:
you will have to duplicate a lot of code to expose all the models properties in the viewmodel.
if you bind the view control to the viewmodels property, you will send the propertyChanged events from the viewmodel. But what happens if the models property change from other source different from the viewmodel setter? Then it has to notify the viewmodel so you end with 2 OnPropertyChanged, one in the model and one in the viewmodel... quite complex!
So for me the correct answer is: it depends on your requirements.
The view model should declare its own properties and hide the specifics of the model from the view. This gives you the most flexibility, and helps keep view model-type issues from leaking into the model classes. Usually your view model classes encapsulate the model by delegation. For example,
class PersonModel {
public string Name { get; set; }
}
class PersonViewModel {
private PersonModel Person { get; set;}
public string Name { get { return this.Person.Name; } }
public bool IsSelected { get; set; } // example of state exposed by view model
public PersonViewModel(PersonModel person) {
this.Person = person;
}
}
Remember: the model shouldn't know anything about the view model that is consuming it, and the view model shouldn't know anything about the view that is consuming it. The view should know nothing about the models lurking in the background. Thus, encapsulate the model behind properties in the view model.
An interesting solution to this was proposed by Robert McCarter in MSDN volume 25.
http://msdn.microsoft.com/en-us/magazine/ff798279.aspx
He uses a dynamic View Model to provide a layer on top of the Model while avoiding proxying all of the Model properties.
If your problem space doesn't require high performance (dynamics do incur a performance hit), this is an excellent solution. The View does not need to know anything about the Model, but the View Model does not have to proxy properties that are being provided "as is." At any time properties can be added to the View Model to wrap the Model properties without modifying the View or the Model. Read the article for more details.
Having a ViewModel for any Model could be worse than that. What if you have a hierarchical structure of a Model, or even a simple collection?
In that case you'll have to iterate through all models and build a ViewModel instance per-model, and also to register notify-change events or other events. IMHO, this is completely insane, and unreasonable. As DaniCE said, you’ll end up with lot of code and a big headache.