If you use some ORM tool like NHibernate and your business entities or DTOs have to support collections of other elements, you are forced to use the interface notation IList<T> or ICollection<T> to hold a reference to the real collection implementation (cause usually those ORM tools tend to inject their own implementation of the collection classes).
Such collections aren’t very well suited to be used in a binding cause they usually doesn’t support any mechanism to inform the binding object that the collection has been changed or altered, so the change is not propagated to the user interface.
You have two way to solve the problem:
1- Convert the collection to a well known ObservableCollection<T>, but in this way you’ll loose the flexibility of having an ORM for your entity cause you’re modifying its normal way to handle object instances.
2- Wrap the ‘ISomething<T>’ collection with another class that exposes all you need to be effective as a binding source for Silverlight or WPF.
I prefer to follow the second approach, cause it eliminates a lot of conversions between objects and preserves objects integrity. Here is a simple implementation of a wrapping class for a generic IList<T> collection:
1: [Serializable]
2: [CollectionDataContract]
3: public class NotifyCollectionWrapper<T> : IList<T>, IList, INotifyCollectionChanged
4: {
5: public NotifyCollectionWrapper()
6: {
7: }
8:
9: public NotifyCollectionWrapper(IList<T> innerlist)
10: {
11: Reset(innerlist);
12: }
13:
14: public NotifyCollectionWrapper<T> Reset(IList<T> innerlist)
15: {
16: _InnerList = innerlist;
17: return this;
18: }
19:
20: private IList<T> _InnerList;
21:
22: #region INotifyCollectionChanged Members
23:
24: public event System.Collections.Specialized.NotifyCollectionChangedEventHandler CollectionChanged;
25:
26: /// <summary>
27: /// Fires the <see cref="CollectionChanged"/> event to indicate an item has been
28: /// added to the end of the collection.
29: /// </summary>
30: /// <param name="item">Item added to the collection.</param>
31: protected void OnItemAdded(T item)
32: {
33: if (this.CollectionChanged != null)
34: {
35: this.CollectionChanged(this, new NotifyCollectionChangedEventArgs(
36: NotifyCollectionChangedAction.Add, item, this.Count - 1));
37: }
38: }
39:
40: /// <summary>
41: /// Fires the <see cref="CollectionChanged"/> event to indicate the collection
42: /// has been reset. This is used when the collection has been cleared or
43: /// entirely replaced.
44: /// </summary>
45: protected void OnCollectionReset()
46: {
47: if (this.CollectionChanged != null)
48: {
49: this.CollectionChanged(this, new NotifyCollectionChangedEventArgs(
50: NotifyCollectionChangedAction.Reset));
51: }
52: }
53:
54: /// <summary>
55: /// Fires the <see cref="CollectionChanged"/> event to indicate an item has
56: /// been inserted into the collection at the specified index.
57: /// </summary>
58: /// <param name="index">Index the item has been inserted at.</param>
59: /// <param name="item">Item inserted into the collection.</param>
60: protected void OnItemInserted(int index, T item)
61: {
62: if (this.CollectionChanged != null)
63: {
64: this.CollectionChanged(this, new NotifyCollectionChangedEventArgs(
65: NotifyCollectionChangedAction.Add, item, index));
66: }
67: }
68:
69: /// <summary>
70: /// Fires the <see cref="CollectionChanged"/> event to indicate an item has
71: /// been replaced into the collection at the specified index.
72: /// </summary>
73: /// <param name="index">Index the item has been inserted at.</param>
74: /// <param name="item">Item inserted into the collection.</param>
75: protected void OnItemReplaced(T newItem, T oldItem, int index)
76: {
77: if (this.CollectionChanged != null)
78: {
79: this.CollectionChanged(this, new NotifyCollectionChangedEventArgs(
80: NotifyCollectionChangedAction.Replace, newItem, oldItem, index));
81: }
82: }
83:
84: /// <summary>
85: /// Fires the <see cref="CollectionChanged"/> event to indicate an item has
86: /// been removed from the collection at the specified index.
87: /// </summary>
88: /// <param name="item">Item removed from the collection.</param>
89: /// <param name="index">Index the item has been removed from.</param>
90: protected void OnItemRemoved(T item, int index)
91: {
92: if (this.CollectionChanged != null)
93: {
94: this.CollectionChanged(this, new NotifyCollectionChangedEventArgs(
95: NotifyCollectionChangedAction.Remove, item, index));
96: }
97: }
98:
99: #endregion
100:
101: #region IList<T> Members
102:
103: public int IndexOf(T item)
104: {
105: return _InnerList.IndexOf(item);
106: }
107:
108: public void Insert(int index, T item)
109: {
110: _InnerList.Insert(index, item);
111: OnItemInserted(index, item);
112: }
113:
114: public T this[int index]
115: {
116: get
117: {
118: return _InnerList[index];
119: }
120:
121: set
122: {
123: T old = _InnerList[index];
124: _InnerList[index] = value;
125: OnItemReplaced(value, old, index);
126: }
127: }
128:
129: public void RemoveAt(int index)
130: {
131: T item = _InnerList[index];
132: _InnerList.RemoveAt(index);
133: OnItemRemoved(item, index);
134: }
135:
136: #endregion
137:
138: #region ICollection<T> Members
139:
140: public void Add(T item)
141: {
142: _InnerList.Add(item);
143: OnItemAdded(item);
144: }
145:
146: public bool Contains(T item)
147: {
148: return _InnerList.Contains(item);
149: }
150:
151: public void CopyTo(T[] array, int arrayIndex)
152: {
153: _InnerList.CopyTo(array, arrayIndex);
154: }
155:
156: public bool Remove(T item)
157: {
158: int index = _InnerList.IndexOf(item);
159: bool result = _InnerList.Remove(item);
160: OnItemRemoved(item, index);
161: return result;
162: }
163:
164: public void Clear()
165: {
166: _InnerList.Clear();
167: OnCollectionReset();
168: }
169:
170: public int Count
171: {
172: get
173: {
174: if (_InnerList != null)
175: return _InnerList.Count;
176: return 0;
177: }
178: }
179:
180: public bool IsReadOnly
181: {
182: get { return _InnerList.IsReadOnly; }
183: }
184:
185: #endregion
186:
187: #region IEnumerable<T> Members
188:
189: IEnumerator<T> IEnumerable<T>.GetEnumerator()
190: {
191: if (_InnerList != null)
192: return _InnerList.GetEnumerator();
193: return null;
194: }
195:
196: #endregion
197:
198: #region IEnumerable Members
199:
200: IEnumerator IEnumerable.GetEnumerator()
201: {
202: return GetEnumerator();
203: }
204:
205: protected IEnumerator GetEnumerator()
206: {
207: if (_InnerList != null)
208: return _InnerList.GetEnumerator();
209: return null;
210: }
211:
212: #endregion
213:
214: #region IList Members
215:
216: public int Add(object value)
217: {
218: _InnerList.Add((T)value);
219: OnItemAdded((T)value);
220: return -1;
221: }
222:
223: public bool Contains(object value)
224: {
225: return _InnerList.Contains((T)value);
226: }
227:
228: public int IndexOf(object value)
229: {
230: return _InnerList.IndexOf((T)value);
231: }
232:
233: public void Insert(int index, object value)
234: {
235: _InnerList.Insert(index, (T)value);
236: OnItemInserted(index, (T)value);
237: }
238:
239: public bool IsFixedSize
240: {
241: get { return false; }
242: }
243:
244: public void Remove(object value)
245: {
246: int index = _InnerList.IndexOf((T)value);
247: bool result = _InnerList.Remove((T)value);
248: OnItemRemoved((T)value, index);
249: }
250:
251: object IList.this[int index]
252: {
253: get
254: {
255: return _InnerList[index];
256: }
257: set
258: {
259: T old = _InnerList[index];
260: _InnerList[index] = (T)value;
261: OnItemReplaced((T)value, old, index);
262: }
263: }
264:
265: #endregion
266:
267: #region ICollection Members
268:
269: public void CopyTo(Array array, int index)
270: {
271: throw new NotImplementedException();
272: }
273:
274: public bool IsSynchronized
275: {
276: get { return false; }
277: }
278:
279: public object SyncRoot
280: {
281: get { return this; }
282: }
283:
284: #endregion
285: }
You can Wrap an IList<T> just creating a new instance of the collection and passing in the reference as a constructor parameter or you can use the Reset() method which will reinitialize the innerList variable to the new collection to be wrapped; in this way you can unleash the full power of binding to a collection that comes directly from an object loaded with an ORM.
Related Content
- Silverlight / WPF: is it possible to bind to an explicit interface indexer implementation? (07/06/2010)
- WPF: force all the validation rules attached to an object to be executed (26/08/2015)
- 'Silverlight in Action' on December, Thursday 11 (12/01/2008)
- Silverlight, M-V-VM … and IoC – part 2 (26/08/2015)
- Silverlight/WPF UIElement: how to find and ancestor of type
procedurally (26/08/2015) - More related document (76)