1
|
/*
|
2
|
Copyright (c) 2003-2008 Niels Kokholm and Peter Sestoft
|
3
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
of this software and associated documentation files (the "Software"), to deal
|
5
|
in the Software without restriction, including without limitation the rights
|
6
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
copies of the Software, and to permit persons to whom the Software is
|
8
|
furnished to do so, subject to the following conditions:
|
9
|
|
10
|
The above copyright notice and this permission notice shall be included in
|
11
|
all copies or substantial portions of the Software.
|
12
|
|
13
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
|
SOFTWARE.
|
20
|
*/
|
21
|
|
22
|
// C5 example: EventPatterns.cs for pattern chapter
|
23
|
|
24
|
// Compile with
|
25
|
// csc /r:C5.dll EventPatterns.cs
|
26
|
|
27
|
using System;
|
28
|
using C5;
|
29
|
using SCG = System.Collections.Generic;
|
30
|
|
31
|
namespace EventPatterns {
|
32
|
class EventPatterns {
|
33
|
public static void Main(String[] args) {
|
34
|
UnindexedCollectionEvents();
|
35
|
Console.WriteLine("--------------------");
|
36
|
IndexedCollectionEvents();
|
37
|
Console.WriteLine("--------------------");
|
38
|
UpdateEvent();
|
39
|
}
|
40
|
|
41
|
public static void UnindexedCollectionEvents() {
|
42
|
ICollection<int> coll = new ArrayList<int>();
|
43
|
ICollection<int> bag1 = new HashBag<int>();
|
44
|
bag1.AddAll(new int[] { 3, 2, 5, 5, 7, 7, 5, 3, 7, 7 });
|
45
|
// Add change handler
|
46
|
coll.CollectionChanged
|
47
|
+= delegate(Object c) {
|
48
|
Console.WriteLine("Collection changed");
|
49
|
};
|
50
|
// Add cleared handler
|
51
|
coll.CollectionCleared
|
52
|
+= delegate(Object c, ClearedEventArgs args) {
|
53
|
Console.WriteLine("Collection cleared");
|
54
|
};
|
55
|
// Add added handler
|
56
|
coll.ItemsAdded
|
57
|
+= delegate(Object c, ItemCountEventArgs<int> args) {
|
58
|
Console.WriteLine("Item {0} added", args.Item);
|
59
|
};
|
60
|
// Add item count handler
|
61
|
AddItemsAddedCounter(coll);
|
62
|
AddItemsRemovedCounter(coll);
|
63
|
coll.AddAll(bag1);
|
64
|
coll.RemoveAll(new int[] { 2, 5, 6, 3, 7, 2 });
|
65
|
coll.Clear();
|
66
|
ICollection<int> bag2 = new HashBag<int>();
|
67
|
// Add added handler with multiplicity
|
68
|
bag2.ItemsAdded
|
69
|
+= delegate(Object c, ItemCountEventArgs<int> args) {
|
70
|
Console.WriteLine("{0} copies of {1} added",
|
71
|
args.Count, args.Item);
|
72
|
};
|
73
|
bag2.AddAll(bag1);
|
74
|
// Add removed handler with multiplicity
|
75
|
bag2.ItemsRemoved
|
76
|
+= delegate(Object c, ItemCountEventArgs<int> args) {
|
77
|
Console.WriteLine("{0} copies of {1} removed",
|
78
|
args.Count, args.Item);
|
79
|
};
|
80
|
bag2.RemoveAllCopies(7);
|
81
|
}
|
82
|
|
83
|
// This works for all kinds of collections, also those with bag
|
84
|
// semantics and representing duplicates by counting:
|
85
|
|
86
|
private static void AddItemsAddedCounter<T>(ICollection<T> coll) {
|
87
|
int addedCount = 0;
|
88
|
coll.ItemsAdded
|
89
|
+= delegate(Object c, ItemCountEventArgs<T> args) {
|
90
|
addedCount += args.Count;
|
91
|
};
|
92
|
coll.CollectionChanged
|
93
|
+= delegate(Object c) {
|
94
|
if (addedCount > 0)
|
95
|
Console.WriteLine("{0} items were added", addedCount);
|
96
|
addedCount = 0;
|
97
|
};
|
98
|
}
|
99
|
|
100
|
// This works for all kinds of collections, also those with bag
|
101
|
// semantics and representing duplicates by counting:
|
102
|
|
103
|
private static void AddItemsRemovedCounter<T>(ICollection<T> coll) {
|
104
|
int removedCount = 0;
|
105
|
coll.ItemsRemoved
|
106
|
+= delegate(Object c, ItemCountEventArgs<T> args) {
|
107
|
removedCount += args.Count;
|
108
|
};
|
109
|
coll.CollectionChanged
|
110
|
+= delegate(Object c) {
|
111
|
if (removedCount > 0)
|
112
|
Console.WriteLine("{0} items were removed", removedCount);
|
113
|
removedCount = 0;
|
114
|
};
|
115
|
}
|
116
|
|
117
|
// Event patterns on indexed collections
|
118
|
|
119
|
public static void IndexedCollectionEvents() {
|
120
|
IList<int> coll = new ArrayList<int>();
|
121
|
ICollection<int> bag = new HashBag<int>();
|
122
|
bag.AddAll(new int[] { 3, 2, 5, 5, 7, 7, 5, 3, 7, 7 });
|
123
|
// Add item inserted handler
|
124
|
coll.ItemInserted
|
125
|
+= delegate(Object c, ItemAtEventArgs<int> args) {
|
126
|
Console.WriteLine("Item {0} inserted at {1}",
|
127
|
args.Item, args.Index);
|
128
|
};
|
129
|
coll.InsertAll(0, bag);
|
130
|
// Add item removed-at handler
|
131
|
coll.ItemRemovedAt
|
132
|
+= delegate(Object c, ItemAtEventArgs<int> args) {
|
133
|
Console.WriteLine("Item {0} removed at {1}",
|
134
|
args.Item, args.Index);
|
135
|
};
|
136
|
coll.RemoveLast();
|
137
|
coll.RemoveFirst();
|
138
|
coll.RemoveAt(1);
|
139
|
}
|
140
|
|
141
|
// Recognizing Update event as a Removed-Added-Changed sequence
|
142
|
|
143
|
private enum State { Before, Removed, Updated };
|
144
|
|
145
|
private static void AddItemUpdatedHandler<T>(ICollection<T> coll) {
|
146
|
State state = State.Before;
|
147
|
T removed = default(T), added = default(T);
|
148
|
coll.ItemsRemoved
|
149
|
+= delegate(Object c, ItemCountEventArgs<T> args) {
|
150
|
if (state==State.Before) {
|
151
|
state = State.Removed;
|
152
|
removed = args.Item;
|
153
|
} else
|
154
|
state = State.Before;
|
155
|
};
|
156
|
coll.ItemsAdded
|
157
|
+= delegate(Object c, ItemCountEventArgs<T> args) {
|
158
|
if (state==State.Removed) {
|
159
|
state = State.Updated;
|
160
|
added = args.Item;
|
161
|
} else
|
162
|
state = State.Before;
|
163
|
};
|
164
|
coll.CollectionChanged
|
165
|
+= delegate(Object c) {
|
166
|
if (state==State.Updated)
|
167
|
Console.WriteLine("Item {0} was updated to {1}",
|
168
|
removed, added);
|
169
|
state = State.Before;
|
170
|
};
|
171
|
}
|
172
|
|
173
|
public static void UpdateEvent() {
|
174
|
ICollection<Teacher> coll = new HashSet<Teacher>();
|
175
|
AddItemUpdatedHandler(coll);
|
176
|
Teacher kristian = new Teacher("Kristian", "physics");
|
177
|
coll.Add(kristian);
|
178
|
coll.Add(new Teacher("Poul Einer", "mathematics"));
|
179
|
// This should be caught by the update handler:
|
180
|
coll.Update(new Teacher("Thomas", "mathematics"));
|
181
|
// This should not be caught by the update handler:
|
182
|
coll.Remove(kristian);
|
183
|
coll.Add(new Teacher("Jens", "physics"));
|
184
|
// The update handler is activated also by indexed updates
|
185
|
IList<int> list = new ArrayList<int>();
|
186
|
list.AddAll(new int[] { 7, 11, 13 });
|
187
|
AddItemUpdatedHandler(list);
|
188
|
list[1] = 9;
|
189
|
}
|
190
|
}
|
191
|
|
192
|
// Example class where objects may be equal yet display differently
|
193
|
|
194
|
class Teacher : IEquatable<Teacher> {
|
195
|
private readonly String name, subject;
|
196
|
|
197
|
public Teacher(String name, String subject) {
|
198
|
this.name = name; this.subject = subject;
|
199
|
}
|
200
|
|
201
|
public bool Equals(Teacher that) {
|
202
|
return this.subject.Equals(that.subject);
|
203
|
}
|
204
|
|
205
|
public override int GetHashCode() {
|
206
|
return subject.GetHashCode();
|
207
|
}
|
208
|
|
209
|
public override String ToString() {
|
210
|
return name + "[" + subject + "]";
|
211
|
}
|
212
|
}
|
213
|
}
|