1/// <summary>
2/// A class which wraps a parent list containing mixed object types, to
3/// provide smaller strongly typed sub-lists of objects.
4/// These sub-lists can be modified, which then modifies the parent list
5/// concurrently (without events being triggered).
6/// <para>Class is serializable</para>.
7/// </summary>
8/// <typeparam name="L">Type of objects in the sub list</typeparam>
9/// <typeparam name="P">The type objects in the parent list
10/// (from which <typeparamref name="L"/> derives or implements) </typeparam>
11[Serializable]
12public sealed class SubList<L, P> : IList<L>
13{
14 private List<P> _parentList;
15 private List<L> _tempList; //memory holder (for enumeration)
16
17 /// <summary>
18 /// For deserializer only. Do not use this constructor.
19 /// </summary>
20 internal protected SubList() { }
21
22 /// <summary>
23 /// List Constructor
24 /// </summary>
25 /// <param name="parentList">Reference to a parent list which contains mixed objects derived from <typeparamref name="P"/></param>
26 public SubList(ref List<P> parentList)
27 {
28 //construct the reference if a null value is passed
29 if (parentList == null)
30 parentList = new List<P>();
31 this._parentList = parentList;
32 }
33
34 /// <summary>
35 /// Create a shallow copy of this sublist to a list of type <typeparamref name="L"/>
36 /// </summary>
37 /// <returns>A strongly typed list copy of the the objects of type <typeparamref name="L"/></returns>
38 public List<L> ShallowCopy()
39 {
40 List<L> ret = new List<L>();
41 this._parentList.ForEach(delegate(P item)
42 {
43 if (item is L)
44 ret.Add((L)(object)item);
45 });
46 return ret;
47 }
48
49 public L[] ToArray()
50 {
51 List<L> ret = this.ShallowCopy();
52 return ret.ToArray();
53 }
54
55 public bool IsParentValid()
56 {
57 return (this._parentList != null);
58 }
59
60 public bool IsValid(L item)
61 {
62 return (this.IsParentValid() && item is P);
63 }
64
65 public void Merge(List<L> list)
66 {
67 list.ForEach(delegate(L item)
68 {
69 if (IsValid(item) && !this._parentList.Contains((P)(object)item))
70 this._parentList.Add((P)(object)item);
71 });
72 }
73 #region IList<L> Members ...
74
75
76 public int IndexOf(L item)
77 {
78 if (IsValid(item))
79 return this._parentList.IndexOf((P)(object)item);
80 return -1;
81 }
82
83 public void Insert(int index, L item)
84 {
85 if (IsValid(item))
86 this._parentList.Insert(index, (P)(object)item);
87 }
88
89 public void RemoveAt(int index)
90 {
91 this._parentList.RemoveAt(index);
92 }
93
94 public L this[int index]
95 {
96 get
97 {
98 P ret = this._parentList[index];
99 if (ret is L)
100 return (L)(object)ret;
101 return default(L);
102 }
103 set
104 {
105 P set = default(P);
106 if (index < this._parentList.Count)
107 set = this._parentList[index];
108 if (set is L || set != null)
109 this._parentList[index] = (P)(object)value;
110 }
111 }
112 #endregion
113 #region ICollection<L> Members ...
114
115
116 public void Add(L item)
117 {
118 if (IsValid(item))
119 this._parentList.Add((P)(object)item);
120 }
121
122 public void Clear()
123 {
124 foreach (P item in this._parentList)
125 if (item is L)
126 this._parentList.Remove((P)(object)item);
127 }
128
129 public bool Contains(L item)
130 {
131 if (IsValid(item))
132 return this._parentList.Contains((P)(object)item);
133 return false;
134 }
135
136 public void CopyTo(L[] array, int arrayIndex)
137 {
138 List<L> ret = this.ShallowCopy();
139 if (ret.Count > 0)
140 ret.CopyTo(array, arrayIndex);
141 }
142
143 public int Count
144 {
145 get
146 {
147 int ret = 0;
148 foreach (P item in this._parentList)
149 if (item is L)
150 ret++;
151 return ret;
152 }
153 }
154
155 bool ICollection<L>.IsReadOnly
156 {
157 get { return ((ICollection<P>)this._parentList).IsReadOnly; }
158 }
159
160 public bool Remove(L item)
161 {
162 if (IsValid(item))
163 return this._parentList.Remove((P)(object)item);
164 return false;
165 }
166 #endregion
167 #region IEnumerable<L> Members ...
168
169
170 IEnumerator<L> IEnumerable<L>.GetEnumerator()
171 {
172 this._tempList = this.ShallowCopy();
173 return this._tempList.GetEnumerator();
174 }
175 #endregion
176 #region IEnumerable Members ...
177
178
179 IEnumerator IEnumerable.GetEnumerator()
180 {
181 return this._parentList.GetEnumerator();
182 }
183 #endregion
184}
185
186//example of how to implement serialization-------------------------------------
187
188[Serializable, DesignerCategory("code")]
189public abstract class Base
190{
191 /// <summary>
192 /// for deserializer only
193 /// </summary>
194 internal Base() { }
195}
196
197[Serializable, DesignerCategory("code")]
198[XmlType("IndexItemAdd")]
199public class Add : Base
200{
201 /// <summary>
202 /// for deserializer only
203 /// </summary>
204 internal Add() : base() { }
205}
206
207[Serializable, DesignerCategory("code")]
208[XmlType("IndexItemDelete")]
209public class Delete : Base
210{
211 /// <summary>
212 /// for deserializer only
213 /// </summary>
214 internal Delete() : base() { }
215}
216
217[Serializable()]
218[DesignerCategory("code")]
219[XmlType("IndexItem")]
220public class IndexItem
221{
222 private List<Base> allItems;
223 private SubList<Add, Base> indexItemAddFields;
224 private SubList<Delete, Base> indexItemDeleteFields;
225
226 [XmlElement("IndexItemAdd")]
227 public SubList<Add, Base> Adds
228 {
229 get { return this.indexItemAddFields; }
230 set
231 {
232 if (value != null && value.IsParentValid())
233 this.indexItemAddFields = value;
234 else
235 this.indexItemAddFields = new SubList<Add, Base>(ref allItems);
236 }
237 }
238
239 [XmlElement("IndexItemDelete")]
240 public SubList<Delete, Base> Deletes
241 {
242 get { return this.indexItemDeleteFields; }
243 set
244 {
245 if (value != null && value.IsParentValid())
246 this.indexItemDeleteFields = value;
247 else
248 this.indexItemDeleteFields = new SubList<Delete, Base>(ref allItems);
249 }
250 }
251
252 [XmlIgnore]
253 public List<Base> Items
254 {
255 get { return this.allItems; }
256 }
257}