1 namespace System.Activities.Presentation
5 using System.Collections.Generic;
7 using System.Activities.Presentation;
10 /// OrderToken is a generic class used to identify the sort
11 /// order of hierarchical items. OrderTokens can be used
12 /// to define priority that is based on some predefined defaults or
13 /// based on other OrderTokens.
15 abstract class OrderToken : IComparable<OrderToken>
18 private readonly OrderToken _reference;
19 private readonly OrderTokenPrecedence _precedence;
20 private readonly OrderTokenConflictResolution _conflictResolution;
22 private readonly int _depth;
23 private readonly int _index;
24 private int _nextChildIndex;
27 /// Creates a new OrderToken instance based on the specified
28 /// referenced OrderToken, precedence, and conflict resolution
31 /// <param name="precedence">Precedence of this token based on the
32 /// referenced token.</param>
33 /// <param name="reference">Referenced token. May be null for the
34 /// root token case (token that's not dependent on anything else).</param>
35 /// <param name="conflictResolution">Conflict resolution semantics.
36 /// Winning ConflictResultion semantic should only be used
37 /// on predefined, default OrderToken instances to ensure
38 /// their correct placement in more complex chain of order
39 /// dependencies.</param>
41 OrderTokenPrecedence precedence,
43 OrderTokenConflictResolution conflictResolution)
46 if (!EnumValidator.IsValid(precedence)) throw FxTrace.Exception.AsError(new ArgumentOutOfRangeException("precedence"));
47 if (!EnumValidator.IsValid(conflictResolution)) throw FxTrace.Exception.AsError(new ArgumentOutOfRangeException("conflictResolution"));
49 _reference = reference;
50 _precedence = precedence;
51 _conflictResolution = conflictResolution;
52 _depth = reference == null ? 0 : reference._depth + 1;
53 _index = reference == null ? -1 : reference._nextChildIndex++;
57 /// Compares this order token with the specified order token.
58 /// The comparsion for OrderTokens that don't belong to the same
59 /// chain of OrderTokens will be resolved non-deterministically.
61 /// <param name="other">The token to compare this token to.</param>
62 /// <returns>0 when the tokens have an equal order priority,
63 /// -1 if this order comes before the specified order,
64 /// 1 otherwise.</returns>
65 /// <exception cref="ArgumentNullException">When other is null</exception>
66 public virtual int CompareTo(OrderToken other)
70 throw FxTrace.Exception.ArgumentNull("other");
75 OrderToken thisOrder = this;
77 // Find a common parent
78 while (thisOrder._reference != other._reference)
81 if (thisOrder._depth == other._depth)
83 thisOrder = thisOrder._reference;
84 other = other._reference;
88 if (thisOrder._depth > other._depth)
90 if (thisOrder._reference == other) return thisOrder._precedence == OrderTokenPrecedence.After ? 1 : -1;
91 thisOrder = thisOrder._reference;
95 if (other._reference == thisOrder) return other._precedence == OrderTokenPrecedence.After ? -1 : 1;
96 other = other._reference;
101 // One order "before", one order "after"? Easy, return the
103 if (thisOrder._precedence != other._precedence)
104 return thisOrder._precedence == OrderTokenPrecedence.Before ? -1 : 1;
106 // Both orders "before" the parent? Roots win, otherwise call ResolveConflict().
107 if (thisOrder._precedence == OrderTokenPrecedence.Before)
109 if (thisOrder._conflictResolution == OrderTokenConflictResolution.Win)
111 else if (other._conflictResolution == OrderTokenConflictResolution.Win)
113 return ResolveConflict(thisOrder, other);
116 // Both orders "after" the parent? Roots win, otherwise call ResolveConflict().
117 if (thisOrder._conflictResolution == OrderTokenConflictResolution.Win)
119 else if (other._conflictResolution == OrderTokenConflictResolution.Win)
121 return ResolveConflict(thisOrder, other);
125 /// This method is called by CompareTo()'s default implementation when two OrderTokens
126 /// appear to be equivalent. The base functionality of this method uses the instantiation
127 /// order of the two tokens as a tie-breaker. Override this method to
128 /// implement custom algorithms. Note that if this method ever returns 0
129 /// (indicating that the two tokens are equivalent) and if these tokens
130 /// belong to a list that gets sorted multiple times, the relative order in
131 /// which they appear in the list will not be guaranteed. This side-effect
132 /// may or may not be a problem depending on the application.
134 /// <param name="left">Left OrderToken</param>
135 /// <param name="right">Right OrderToken</param>
136 /// <returns>0, if the two are equal, -1, if left comes before right,
137 /// 1 otherwise.</returns>
138 protected virtual int ResolveConflict(OrderToken left, OrderToken right)
140 return left._index.CompareTo(right._index);