File: src\Framework\System\Windows\Controls\ContainerTracking.cs
Project: wpf\PresentationFramework.csproj (PresentationFramework)
//---------------------------------------------------------------------------
//
// Copyright (C) Microsoft Corporation.  All rights reserved.
//
//---------------------------------------------------------------------------
 
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
 
namespace System.Windows.Controls
{
    /// <summary>
    ///     Represents a node in a linked list used to track active containers.
    ///     Containers should instantiate and references these.
    ///     Parents hold onto the linked list.
    ///     
    ///     The list is iterated in order to call a variety of methods on containers
    ///     in response to changes on the parent.
    /// </summary>
    internal class ContainerTracking<T>
    {
        internal ContainerTracking(T container)
        {
            _container = container;
        }
 
        /// <summary>
        ///     The row container that this object represents.
        /// </summary>
        internal T Container
        {
            get { return _container; }
        }
 
        /// <summary>
        ///     The next node in the list.
        /// </summary>
        internal ContainerTracking<T> Next
        {
            get { return _next; }
        }
 
        /// <summary>
        ///     The previous node in the list.
        /// </summary>
        internal ContainerTracking<T> Previous
        {
            get { return _previous; }
        }
 
        /// <summary>
        ///     Adds this tracker to the list of active containers.
        /// </summary>
        /// <param name="root">The root of the list.</param>
        internal void StartTracking(ref ContainerTracking<T> root)
        {
            // Add the node to the root
            if (root != null)
            {
                root._previous = this;
            }
 
            _next = root;
            root = this;
        }
 
        /// <summary>
        ///     Removes this tracker from the list of active containers.
        /// </summary>
        /// <param name="root">The root of the list.</param>
        internal void StopTracking(ref ContainerTracking<T> root)
        {
            // Unhook the node from the list
            if (_previous != null)
            {
                _previous._next = _next;
            }
 
            if (_next != null)
            {
                _next._previous = _previous;
            }
 
            // Update the root reference
            if (root == this)
            {
                root = _next;
            }
 
            // Clear the node's references
            _previous = null;
            _next = null;
        }
 
        #region Debugging Helpers
        
        /// <summary>
        ///     Asserts that the container represented by this tracker is in the list represented by the given root.
        /// </summary>
        [Conditional("DEBUG")]
        internal void Debug_AssertIsInList(ContainerTracking<T> root)
        {
#if DEBUG
            Debug.Assert(IsInList(root), "This container should be in the tracking list.");
#endif
        }
 
        /// <summary>
        ///     Asserts that the container represented by this tracker is not in the list represented by the given root.
        /// </summary>
        [Conditional("DEBUG")]
        internal void Debug_AssertNotInList(ContainerTracking<T> root)
        {
#if DEBUG
            Debug.Assert(!IsInList(root), "This container shouldn't be in our tracking list");
#endif
        }
 
#if DEBUG
        /// <summary>
        ///     Checks that this tracker is present in the list starting with root.  It's a linear walk through the list, so should be used
        ///     mostly for debugging
        /// </summary>
        private bool IsInList(ContainerTracking<T> root)
        {
            ContainerTracking<T> node = root;
 
            while (node != null)
            {
                if (node == this)
                {
                    return true;
                }
 
                node = node._next;
            }
 
            return false;
        }
#endif
 
        #endregion
 
        private T _container;
        private ContainerTracking<T> _next;
        private ContainerTracking<T> _previous;
    }
}