GraphLinksModelNodeData implementation

I can’t use the built-in GraphLinksModelNodeData<> class (existing structure).

I have implemented my own, but some things don’t work properly.

Could you please give me the implementation of this class ?



You need to implement INotifyPropertyChanged, IChangeDataValue, and ICloneable.

[code] ///

/// This event implements the interface,
/// so that both the model and the dependency object system can be informed
/// of changes to property values.

[field: NonSerializedAttribute()]
public event PropertyChangedEventHandler PropertyChanged;

/// <summary>
/// Raise the <see cref="PropertyChanged"/> event.
/// </summary>
/// <param name="e"></param>
public virtual void OnPropertyChanged(ModelChangedEventArgs e) {
  if (this.PropertyChanged != null) this.PropertyChanged(this, e);

/// <summary>
/// Call this method from property setters to raise the <see cref="PropertyChanged"/> event.
/// </summary>
/// <param name="pname">the property name</param>
/// <param name="oldval">the value before the property was set</param>
/// <param name="newval">the new value</param>
/// <remarks>
/// Only call this method when the property value actually changes.
/// The <paramref name="oldval"/> and <paramref name="newval"/> values are needed
/// to support undo/redo.
/// </remarks>
protected void RaisePropertyChanged(String pname, Object oldval, Object newval) {
  OnPropertyChanged(new ModelChangedEventArgs(pname, this, oldval, newval));

/// <summary> /// This method implements the <see cref="IChangeDataValue"/> interface, /// used to perform state changes for undo and redo. /// </summary> /// <param name="e">an edit describing the change to be performed</param> /// <param name="undo">true if undoing; false if redoing</param> /// <remarks> /// Unless you override this method to explicitly handle each property that you define, /// this implementation uses reflection to set the property. /// </remarks> public virtual void ChangeDataValue(ModelChangedEventArgs e, bool undo) { if (e == null) return; if (e.PropertyName == "Location") { this.Location = (Point)e.GetValue(undo); } else if (e.PropertyName == "Text") { this.Text = (String)e.GetValue(undo); } else if (e.PropertyName == "Key") { this.Key = (NodeKey)e.GetValue(undo); } else if (e.PropertyName == "IsSubGraph") { this.IsSubGraph = (bool)e.GetValue(undo); } else if (e.PropertyName == "IsSubGraphExpanded") { this.IsSubGraphExpanded = (bool)e.GetValue(undo); } else if (e.PropertyName == "WasSubGraphExpanded") { this.WasSubGraphExpanded = (bool)e.GetValue(undo); } else if (e.PropertyName == "SubGraphKey") { this.SubGraphKey = (NodeKey)e.GetValue(undo); } else if (e.PropertyName == "MemberKeys") { this.MemberKeys = (IList<NodeKey>)e.GetValue(undo); } else if (e.PropertyName == "IsLinkLabel") { this.IsLinkLabel = (bool)e.GetValue(undo); } else if (e.PropertyName == "Category") { this.Category = (String)e.GetValue(undo); } else if (e.Change == ModelChange.Property) { if (!ModelHelper.SetProperty(e.PropertyName, e.Data, e.GetValue(undo))) { ModelHelper.Error("ERROR: Unrecognized property name: " + e.PropertyName != null ? e.PropertyName : "(noname)" + " in GraphLinksModelNodeData.ChangeDataValue"); } } }

/// <summary> /// Create a copy of this data; this implements the <c>ICloneable</c> interface. /// </summary> /// <returns></returns> /// <remarks> /// <para> /// When you add your own state in a subclass, and when you expect to be able to copy the data, /// you should override this method in your derived class when it has some fields that are object references. /// Your override method should first call <c>base.Clone()</c> to get the newly copied object. /// The result should be the object you return, /// after performing any other deeper copying of referenced objects that you deem necessary, /// and after removing references that should not be shared (such as to cached data structures). /// </para> /// <para> /// The standard implementation of this method is to do a shallow copy, by <c>Object.MemberwiseClone()</c>, /// and reinitialize the <see cref="SubGraphKey"/> and <see cref="MemberKeys"/> properties. /// You do not need to override this method if you have only added some fields/properties /// that are values or are references to intentionally shared objects. /// </para> /// </remarks> public virtual object Clone() { GraphLinksModelNodeData<NodeKey> d = (GraphLinksModelNodeData<NodeKey>)MemberwiseClone(); d.PropertyChanged = null; d._SubGraphKey = default(NodeKey); d._MemberKeys = new ObservableCollection<NodeKey>(); return d; }

Thanks for information. But I note the code references GoXam types (ModelChangedEventArgs, ModelHelper) and that is a problem for me. I think is better to explain what I try to do, it can be interesting for other people.

I think it is a MVVM problem and I am newbie in this domain.

A simplified drawing of my system:


1) Adding a node in the GoXam ‘world’ fires a AddedNode event with a CommonNodeViewModel object as parameter.

2) In the TreeView ‘world’ a node is added.

3) A node in the TreeView is selected passing the corresponding CommonNodeViewModel to the NodeDataEditorControl.

4) At this point, a data modification via the Data Editor will be propagated int the TreeView and GoXam diagram through the RaisePropertyChanged in the CommonNodeViewModel.

So my problem is how to implement a class that behave like a GraphLinksModelNodeData in this MVVM context.

I am testing with the following structure:

It simple, but I must maintain few properties values between the GraphLinksModelNodeData object and my CommonNodeViewModel object.

What’s the problem with using ModelChangedEventArgs?

The ModelHelper class is internal to GoXam, but you don’t need it.

It seems to me you could either replace your CommonNodeViewModel class with the GoXamNodeViewModel, or you could replace your GoXamNodeViewModel with your CommonNodeViewModel.

It isn’t clear to me that you really need the TreeViewNodeViewModel class either, although I haven’t thought enough about how to change TreeView to work with models.

Well… my goal is to have minimal coupling between types and easy expandability.

For example I must be able to select and expand a node in the tree view without selecting or expanding the corresponding node in GoXam diagram. So the class TreeViewNodeViewModel must have two properties IsSelected and IsExpanded that have a meaning only in the Tree View Context. More, the TreeViewNodeViewModel class can have for example accessors to return child nodes collection, leaving links collection or other specific data.

What if later I must add some ListView Control to show (for example) all model items in some customizable order?

I can “merge” all my 3 ViewModel classes in one, but I am afraid It will result in some unmaintainable swiss army knife class.

Thanks anyway for your comments. More I explain, better I understand. :-)