File: System\Data\DataViewListener.cs
Project: ndp\fx\src\data\System.Data.csproj (System.Data)
//------------------------------------------------------------------------------
// <copyright file="Select.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
// <owner current="true" primary="true">Microsoft</owner>
// <owner current="true" primary="false">Microsoft</owner>
//------------------------------------------------------------------------------
 
namespace System.Data {
 
    using System;
    using System.ComponentModel;
    using System.Collections.Generic;
    using System.Diagnostics;
 
    internal sealed class DataViewListener {
 
        private readonly WeakReference _dvWeak;
        private DataTable _table;
        private Index _index;
 
        /// <summary><see cref="DataView.ObjectID"/></summary>
        internal readonly int ObjectID;
 
        internal DataViewListener(DataView dv) {
            this.ObjectID = dv.ObjectID;
            _dvWeak = new WeakReference(dv);
        }
 
        private void ChildRelationCollectionChanged(object sender, CollectionChangeEventArgs e) {
            DataView dv = (DataView)_dvWeak.Target;
            if (dv != null) {
                dv.ChildRelationCollectionChanged(sender, e);
            }
            else {
                CleanUp(true);
            }
        }
 
        private void ParentRelationCollectionChanged(object sender, CollectionChangeEventArgs e) {
            DataView dv = (DataView)_dvWeak.Target;
            if (dv != null) {
                dv.ParentRelationCollectionChanged(sender, e);
            }
            else {
                CleanUp(true);
            }
        }
 
        private void ColumnCollectionChanged(object sender, CollectionChangeEventArgs e) {
            DataView dv = (DataView)_dvWeak.Target;
            if (dv != null) {
                dv.ColumnCollectionChangedInternal(sender, e);
            }
            else {
                CleanUp(true);
            }
        }
 
        /// <summary>
        /// Maintain the DataView before <see cref="DataView.ListChanged"/> is raised.
        /// </summary>
        internal void MaintainDataView(ListChangedType changedType, DataRow row, bool trackAddRemove) {
            DataView dv = (DataView)_dvWeak.Target;
            if (dv != null) {
                dv.MaintainDataView(changedType, row, trackAddRemove);
            }
            else {
                CleanUp(true);
            }
        }
 
        internal void IndexListChanged(ListChangedEventArgs e) {
            DataView dv = (DataView)_dvWeak.Target;
            if (dv != null) {
                dv.IndexListChangedInternal(e);
            }
            else {
                CleanUp(true);
            }
        }
 
        internal void RegisterMetaDataEvents(DataTable table) {
            Debug.Assert(null == _table, "DataViewListener already registered table");
            _table = table;
            if (table != null) {
                // actively remove listeners without a target
                RegisterListener(table);
 
                // start listening to events
                CollectionChangeEventHandler handlerCollection = new CollectionChangeEventHandler(ColumnCollectionChanged);
                table.Columns.ColumnPropertyChanged += handlerCollection;
                table.Columns.CollectionChanged += handlerCollection;
 
                CollectionChangeEventHandler handlerChildRelation = new CollectionChangeEventHandler(ChildRelationCollectionChanged);
                ((DataRelationCollection.DataTableRelationCollection)(table.ChildRelations)).RelationPropertyChanged += handlerChildRelation;
                table.ChildRelations.CollectionChanged += handlerChildRelation;
 
                CollectionChangeEventHandler handlerParentRelation = new CollectionChangeEventHandler(ParentRelationCollectionChanged);
                ((DataRelationCollection.DataTableRelationCollection)(table.ParentRelations)).RelationPropertyChanged += handlerParentRelation;
                table.ParentRelations.CollectionChanged += handlerParentRelation;
            }
        }
 
        internal void UnregisterMetaDataEvents() {
            UnregisterMetaDataEvents(true);
        }
 
        private void UnregisterMetaDataEvents(bool updateListeners) {
            DataTable table = _table;
            _table = null;
 
            if (table != null) {
                CollectionChangeEventHandler handlerCollection = new CollectionChangeEventHandler(ColumnCollectionChanged);
                table.Columns.ColumnPropertyChanged -= handlerCollection;
                table.Columns.CollectionChanged -= handlerCollection;
 
                CollectionChangeEventHandler handlerChildRelation = new CollectionChangeEventHandler(ChildRelationCollectionChanged);
                ((DataRelationCollection.DataTableRelationCollection)(table.ChildRelations)).RelationPropertyChanged -= handlerChildRelation;
                table.ChildRelations.CollectionChanged -= handlerChildRelation;
 
                CollectionChangeEventHandler handlerParentRelation = new CollectionChangeEventHandler(ParentRelationCollectionChanged);
                ((DataRelationCollection.DataTableRelationCollection)(table.ParentRelations)).RelationPropertyChanged -= handlerParentRelation;
                table.ParentRelations.CollectionChanged -= handlerParentRelation;
 
                if (updateListeners) {
                    List<DataViewListener> listeners = table.GetListeners();
                    lock (listeners) {
                        listeners.Remove(this);
                    }
                }
            }
        }
 
        internal void RegisterListChangedEvent(Index index) {
            Debug.Assert(null == _index, "DataviewListener already registered index");
            _index = index;
            if (null != index) {
                lock (index) {
                    index.AddRef();
                    index.ListChangedAdd(this);
                }
            }
        }
 
        internal void UnregisterListChangedEvent() {
            Index index = _index;
            _index = null;
 
            if (index != null) {
                lock (index) {
                    index.ListChangedRemove(this);
                    if (index.RemoveRef() <= 1) {
                        index.RemoveRef();
                    }
                }
            }
        }
 
        private void CleanUp(bool updateListeners) {
            UnregisterMetaDataEvents(updateListeners);
            UnregisterListChangedEvent();
        }
 
        private void RegisterListener(DataTable table) {
            List<DataViewListener> listeners = table.GetListeners();
            lock (listeners) {
                for (int i = listeners.Count - 1; 0 <= i; --i) {
                    DataViewListener listener = listeners[i];
                    if (!listener._dvWeak.IsAlive) {
                        listeners.RemoveAt(i);
                        listener.CleanUp(false);
                    }
                }
                listeners.Add(this);
            }
        }
    }
}