158 lines
4.5 KiB
C#
158 lines
4.5 KiB
C#
|
//---------------------------------------------------------------------------
|
||
|
//
|
||
|
// 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;
|
||
|
using System.Windows.Controls.Primitives;
|
||
|
using System.Windows.Input;
|
||
|
using EGC = ExtendedGrid.Microsoft.Windows.Controls;
|
||
|
|
||
|
namespace ExtendedGrid.Microsoft.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 EGC.ContainerTracking<T> Next
|
||
|
{
|
||
|
get { return _next; }
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// The previous node in the list.
|
||
|
/// </summary>
|
||
|
internal EGC.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 EGC.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 EGC.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(EGC.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(EGC.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(EGC.ContainerTracking<T> root)
|
||
|
{
|
||
|
EGC.ContainerTracking<T> node = root;
|
||
|
|
||
|
while (node != null)
|
||
|
{
|
||
|
if (node == this)
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
node = node._next;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
private T _container;
|
||
|
private EGC.ContainerTracking<T> _next;
|
||
|
private EGC.ContainerTracking<T> _previous;
|
||
|
}
|
||
|
}
|