mganss / XmlSchemaClassGenerator

Generate C# classes from XML Schema files
Apache License 2.0
589 stars 179 forks source link

Question: EnableDataBinding & ObservableCollection<T>.CollectionChanged Event #523

Closed djwork closed 2 months ago

djwork commented 2 months ago

Hi mganss 1st off thanks for all your hard work on XmlSchemaClassGenerator. I have been expirementing with the EnableDataBinding option and I can see generated code for Collection properties:

//EnableDataBinding == true
//CollectionSettersMode = Public
public System.Collections.ObjectModel.Collection<MyElementType> MyElement
{
    get
    {
        return _myelement;
    }
    set
    {
        if (_myelement == value)
            return;
        if (_myelement == null || value == null || !_myelement.SequenceEqual(value))
        {
        _myelement = value;
            OnPropertyChanged();
        }
    }
}

The problem for what I am trying todo is that OnPropertyChanged would only be called if the setter is made public and the entire collection is replaced with a ref to another collection.

What I want todo is to have an onchange event that fires when the collection's list elements change.

I was able to use the CollectionType Setting to change from the default collection type to System.Collections.ObjectModel.ObservableCollection which has both a PropertyChanged and a CollectionChanged Event.

But short of using relection I don't have an way of assigning delegates to all of the generated Collection properties (like what happens to the non-collection properties when EnableDataBinding is used).

Any suggestions?

mganss commented 2 months ago

I think I don't understand the use case completely yet. Why do you have to use reflection to subscribe to the CollectionChanged event?

djwork commented 2 months ago

I don't need to use reflection to subscribe to CollectionChanged but currently I need to use it to find which of the containing class's properties implement INotifyCollectionChanged.

But anyhow I think I can do most of what I want to if I can get the XML Container classes PropertyChanged event to fire when a collection property is changed.

Something like when EnableDataBinding and CollectionType implements System.Collections.Specialized.INotifyCollectionChanged Add private method OnCollectionChangedPropertyChanged with a if statement per collection property Add to the container constructor for each collection property append OnCollectionChangedPropertyChanged to collection.CollectionChanged

What do you think?

//EnableDataBinding == true
//CollectionType implements System.Collections.Specialized.INotifyCollectionChanged
public partial class MyContainer : System.ComponentModel.INotifyPropertyChanged
{

  public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;

  protected virtual void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberNameAttribute()] string propertyName = null)
  {
    PropertyChanged?.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
  }

  private void OnCollectionChangedPropertyChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
  {
    if (sender == this.MyElement1s)
    {
      this.OnPropertyChanged(nameof(this.MyElement1s));
    }
    elseif (sender == this.MyElement2s)
    {
      this.OnPropertyChanged(nameof(this.MyElement2s));
    }
  }

  [System.Xml.Serialization.XmlIgnoreAttribute()]
  private DataSettingsType _settings;

  [System.ComponentModel.DataAnnotations.RequiredAttribute(AllowEmptyStrings = true)]
  [System.Xml.Serialization.XmlElementAttribute("Settings", Order = 0)]
  public DataSettingsType Settings
  {
    get
    {
      return _settings;
    }
    set
    {
      if (_settings == value)
        return;
      if (_settings == null || value == null || !_settings.Equals(value))
      {
        _settings = value;
        OnPropertyChanged();
      }
    }
  }

  [System.Xml.Serialization.XmlIgnoreAttribute()]
  private System.Collections.ObjectModel.ObservableCollection<MyElement1Type> _myelement1;

  [System.ComponentModel.DataAnnotations.RequiredAttribute(AllowEmptyStrings = true)]
  [System.Xml.Serialization.XmlArrayAttribute("MyElement1s", Order = 1)]
  [System.Xml.Serialization.XmlArrayItemAttribute("MyElement1", Namespace = "http://www.aemo.com.au/Simulator/MyContainer")]
  public System.Collections.ObjectModel.ObservableCollection<MyElement1Type> MyElement1s
  {
    get
    {
      return _myelement1;
    }
    private set
    {
      if (_myelement1 == value)
        return;
      if (_myelement1 == null || value == null || !_myelement1.SequenceEqual(value))
      {
        _myelement1 = value;
        OnPropertyChanged();
      }
    }
  }

  [System.Xml.Serialization.XmlIgnoreAttribute()]
  private System.Collections.ObjectModel.ObservableCollection<MyElement2Type> _myelement2;

  [System.ComponentModel.DataAnnotations.RequiredAttribute(AllowEmptyStrings = true)]
  [System.Xml.Serialization.XmlArrayAttribute("MyElement2s", Order = 2)]
  [System.Xml.Serialization.XmlArrayItemAttribute("MyElement2", Namespace = "http://www.aemo.com.au/Simulator/MyContainer")]
  public System.Collections.ObjectModel.ObservableCollection<MyElement2Type> MyElement2s
  {
    get
    {
      return _myelement2;
    }
    private set
    {
      if (_myelement2 == value)
        return;
      if (_myelement2 == null || value == null || !_myelement2.SequenceEqual(value))
      {
        _myelement2 = value;
        OnPropertyChanged();
      }
    }
  }

  /// <summary>
  /// <para xml:lang="en">Initializes a new instance of the <see cref="MyContainer" /> class.</para>
  /// </summary>
  public MyContainer()
  {
    this._myelement1 = new System.Collections.ObjectModel.ObservableCollection<MyElement1Type>();
    if (this._myelement1 is System.Collections.Specialized.INotifyCollectionChanged)
    {
      this._myelement1.CollectionChanged += this.OnCollectionChangedPropertyChanged;
    }

    this._myelement2 = new System.Collections.ObjectModel.ObservableCollection<MyElement2Type>();
    if (this._myelement2 is System.Collections.Specialized.INotifyCollectionChanged)
    {
      this._myelement2.CollectionChanged += this.OnCollectionChangedPropertyChanged;
    }
  }
}
mganss commented 2 months ago

I think this is outside of the scope of XmlSchemaClassGenerator.