1

Does anybody know an easy way to keep a viewmodel in sync with an XDocument which is constantly changing? The XDocument is coming from the Microsoft.VisualStudio.XmlEditor.XmlModel class (http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.xmleditor.xmlmodel.aspx). The same XDocument is constantly updated when a user is changing text in the visual studio editor.

I don't want to use serialisation to parse every time the whole xml into objects. The document is very, and that would be a big performance bottleneck.

This question is somehow similar to my question, but what to fill in on "(helper)"? ViewModel on top of XDocument

Requirements: - The viewmodel must be updated when something in the XDocument tree is changed, and minimum changes must be applied. - Events when a child of an object is changed. - Observablecollections when there are multiple same child tags - Objects must be reused, no new elements each time objects are accessed made from my custom classes. So properties must be used to hold the generated object from xml. The object must be updated with the new childs.

Is there a framework or something available to do this task in an easy way? I think many people have already done something like this, and I don't want to re-invent the wheel.

I hope this question is a little bit clear.

Community
  • 1
  • 1
TWT
  • 2,511
  • 1
  • 23
  • 37
  • For starters, every `XObject` has a `Changed` and a `Changing` event. If you could somehow subscribe to these events for every child element you're interested in, you could easily use the events and the observer pattern to update your UI. – Cᴏʀʏ Jan 23 '13 at 22:11
  • Do you have an example for me? – TWT Jan 23 '13 at 22:14
  • http://msdn.microsoft.com/en-us/library/system.xml.linq.xobject.changing.aspx – Cᴏʀʏ Jan 23 '13 at 22:15
  • Ok thanks. But I still think there must be something available to do that automaticly for me. Keeping an IEnumerable in sync with an ObservableCollection, and only create a new instance of that class for new XElements, is not easy with those events. Also the order in the ObservableCollection must be the same as in the XDocument. – TWT Jan 23 '13 at 22:19

1 Answers1

0

You could write your ViewModel around an XElement.

For example,

public class Model {

   protected XElement Element {
     get; set;
   }

   public Model() : this(null) { }

   public Model(XElement element) {
     // do some validation (XName)element.Name
     this.Element = element ?? new XElement("Model");
   }

   public string Name {
     get {
       return (string)Element.Attribute("Name");
     }
     set {
       // null: attribute is removed
       Element.SetAttributeValue(value);
     }
   }
}

Your Xml:

<Model Name="Marilyn" />

Using your XDocument you can read in your elements:

source.Select(xElement => new Model(xElement));

The ObservableCollection itself gets notified by INotifyPropertyChanged pattern:

public event PropertyChangedEventHandler PropertyChanged;

protected virtual void OnPropertyChanged(string propertyName)
{
    var handler = PropertyChanged;
    if (handler != null)
        handler(this, new PropertyChangedEventArgs(propertyName));
}

In your Model, you get notified by XObject.Change and .Changed events, that you assign in your constructor:

public Model() : this(null) {
  // call public Model(XElement element = null)
}

public Model(XElement element) {
  // do some validation (XName)element.Name
  this.Element = element ?? new XElement("Model");
  //this.Element.Changing += Element_Changing;
  this.Element.Changed += Element_Changed;
}

Now you can connect XElement changes to INotifyProperty changes:

protected void Element_Changed(object sender, XObjectChangeEventArgs ea) {
  var attribute = sender as XAttribute;
  if (attribute != null && attribute.Parent == this.Element) {
    // only attributes of this element (and not the nested elements)
    // the attribute name is assumed to be exactly same as property name 'Name'
    OnPropertyChanged(attribute.Name);
  }
}

Beware that the Changed and Changing are bubbeling up, so you may watch only your XDocument.Root XElement or your Model.Element XElement.

A little bit oversimplified, I hope to give you an idea what that might look like. Now, .NET Framwork is yours.

I found good examples at:

Community
  • 1
  • 1
metadings
  • 3,798
  • 2
  • 28
  • 37