CSLA.NET 6.0.0
CSLA .NET is a software development framework that helps you build a reusable, maintainable object-oriented business layer for your app.
ObservableBindingList.cs
Go to the documentation of this file.
1//-----------------------------------------------------------------------
2// <copyright file="ObservableBindingList.cs" company="Marimer LLC">
3// Copyright (c) Marimer LLC. All rights reserved.
4// Website: https://cslanet.com
5// </copyright>
6// <summary>Extends ObservableCollection with behaviors required</summary>
7//-----------------------------------------------------------------------
8using System;
9using System.ComponentModel;
10using System.Collections.Generic;
11using System.Linq;
12using System.Text;
13using System.Reflection;
16using Csla.Core;
17using System.Collections.ObjectModel;
18using System.Collections.Specialized;
19using System.ComponentModel.DataAnnotations;
20using Csla.Properties;
21using System.Diagnostics;
22
23namespace Csla.Core
24{
36 {
37 #region SupportsChangeNotification
38
39 private bool _supportsChangeNotificationCore = true;
44 protected virtual bool SupportsChangeNotificationCore { get { return _supportsChangeNotificationCore; } }
45
46 #endregion
47
48 #region AddNew
49
50 private bool _raiseListChangedEvents = true;
51
56 public bool AllowEdit
57 {
58 get { return _allowEdit; }
59 protected set { _allowEdit = value; }
60 }
61
66 public bool AllowNew
67 {
68 get { return _allowNew; }
69 protected set { _allowNew = value; }
70 }
71
76 public bool AllowRemove
77 {
78 get { return _allowRemove; }
79 protected set { _allowRemove = value; }
80 }
81
87 {
88 get { return _raiseListChangedEvents; }
89 set { _raiseListChangedEvents = value; }
90 }
91
95 public T AddNew()
96 {
97 var result = AddNewCore();
98 OnAddedNew(result);
99 return result;
100 }
101
103 {
104 return AddNew();
105 }
106
107 #endregion
108
109 #region RemovingItem event
110
111 [NonSerialized()]
112 private EventHandler<RemovingItemEventArgs> _removingItemHandler;
113
117 public event EventHandler<RemovingItemEventArgs> RemovingItem
118 {
119 add
120 {
121 _removingItemHandler = (EventHandler<RemovingItemEventArgs>)
122 System.Delegate.Combine(_removingItemHandler, value);
123 }
124 remove
125 {
126 _removingItemHandler = (EventHandler<RemovingItemEventArgs>)
127 System.Delegate.Remove(_removingItemHandler, value);
128 }
129 }
130
138 [EditorBrowsable(EditorBrowsableState.Advanced)]
139 protected void OnRemovingItem(T removedItem)
140 {
141 if (_removingItemHandler != null)
142 _removingItemHandler.Invoke(this,
143 new RemovingItemEventArgs(removedItem));
144 }
145
146 #endregion
147
148 #region RemoveItem
149
158 protected override void RemoveItem(int index)
159 {
160 OnRemovingItem(this[index]);
161 OnRemoveEventHooks(this[index]);
162 base.RemoveItem(index);
163 }
164
165 #endregion
166
167 #region AddRange
168
173 public void AddRange(System.Collections.Generic.IEnumerable<T> range)
174 {
175 foreach (var element in range)
176 this.Add(element);
177 }
178
179 #endregion
180
181 #region INotifyPropertyBusy Members
182
183 [NotUndoable]
184 [NonSerialized]
185 private BusyChangedEventHandler _busyChanged = null;
186
192 {
193 add { _busyChanged = (BusyChangedEventHandler)Delegate.Combine(_busyChanged, value); }
194 remove { _busyChanged = (BusyChangedEventHandler)Delegate.Remove(_busyChanged, value); }
195 }
196
202 protected virtual void OnBusyChanged(BusyChangedEventArgs args)
203 {
204 if (_busyChanged != null)
205 _busyChanged(this, args);
206 }
207
213 protected void OnBusyChanged(string propertyName, bool busy)
214 {
215 OnBusyChanged(new BusyChangedEventArgs(propertyName, busy));
216 }
217
221 [Browsable(false)]
222 [Display(AutoGenerateField = false)]
223 [ScaffoldColumn(false)]
224 public virtual bool IsBusy
225 {
226 get { return false; }
227 }
228
232 [Browsable(false)]
233 [Display(AutoGenerateField = false)]
234 [ScaffoldColumn(false)]
235 public virtual bool IsSelfBusy
236 {
237 get { return IsBusy; }
238 }
239
240 void busy_BusyChanged(object sender, BusyChangedEventArgs e)
241 {
242 OnBusyChanged(e);
243 }
244
245 #endregion
246
247 #region INotifyUnhandledAsyncException Members
248
249 [NotUndoable]
250 [NonSerialized]
251 private EventHandler<ErrorEventArgs> _unhandledAsyncException;
252
257 public event EventHandler<ErrorEventArgs> UnhandledAsyncException
258 {
259 add { _unhandledAsyncException = (EventHandler<ErrorEventArgs>)Delegate.Combine(_unhandledAsyncException, value); }
260 remove { _unhandledAsyncException = (EventHandler<ErrorEventArgs>)Delegate.Remove(_unhandledAsyncException, value); }
261 }
262
268 protected virtual void OnUnhandledAsyncException(ErrorEventArgs error)
269 {
270 if (_unhandledAsyncException != null)
271 _unhandledAsyncException(this, error);
272 }
273
279 protected void OnUnhandledAsyncException(object originalSender, Exception error)
280 {
281 OnUnhandledAsyncException(new ErrorEventArgs(originalSender, error));
282 }
283
284 void unhandled_UnhandledAsyncException(object sender, ErrorEventArgs e)
285 {
287 }
288
289 #endregion
290
291 #region AddChildHooks
292
298 protected override void InsertItem(int index, T item)
299 {
300 base.InsertItem(index, item);
301 OnAddEventHooks(item);
302 }
303
309 [EditorBrowsable(EditorBrowsableState.Never)]
310 protected virtual void OnAddEventHooks(T item)
311 {
312 INotifyBusy busy = item as INotifyBusy;
313 if (busy != null)
314 busy.BusyChanged += new BusyChangedEventHandler(busy_BusyChanged);
315
317 if (unhandled != null)
318 unhandled.UnhandledAsyncException += new EventHandler<ErrorEventArgs>(unhandled_UnhandledAsyncException);
319
320 INotifyPropertyChanged c = item as INotifyPropertyChanged;
321 if (c != null)
322 c.PropertyChanged += Child_PropertyChanged;
323
324 //IBindingList list = item as IBindingList;
325 //if (list != null)
326 // list.ListChanged += new ListChangedEventHandler(Child_ListChanged);
327
329 if (child != null)
330 child.ChildChanged += Child_Changed;
331 }
332
338 [EditorBrowsable(EditorBrowsableState.Never)]
339 protected virtual void OnRemoveEventHooks(T item)
340 {
341 INotifyBusy busy = item as INotifyBusy;
342 if (busy != null)
343 busy.BusyChanged -= new BusyChangedEventHandler(busy_BusyChanged);
344
346 if (unhandled != null)
347 unhandled.UnhandledAsyncException -= new EventHandler<ErrorEventArgs>(unhandled_UnhandledAsyncException);
348
349 INotifyPropertyChanged c = item as INotifyPropertyChanged;
350 if (c != null)
351 c.PropertyChanged -= Child_PropertyChanged;
352
353 //IBindingList list = item as IBindingList;
354 //if(list!=null)
355 // list.ListChanged -= new ListChangedEventHandler(Child_ListChanged);
356
358 if (child != null)
359 child.ChildChanged -= new EventHandler<ChildChangedEventArgs>(Child_Changed);
360 }
361
362 #endregion
363
364 #region ISerializationNotification Members
365
370 [EditorBrowsable(EditorBrowsableState.Advanced)]
371 protected virtual void OnDeserialized()
372 {
373 // do nothing - this is here so a subclass
374 // could override if needed
375 }
376
377 [System.Runtime.Serialization.OnDeserialized]
378 private void OnDeserializedHandler(System.Runtime.Serialization.StreamingContext context)
379 {
380 foreach (T item in this)
381 OnAddEventHooks(item);
382
384 }
385
387 {
388 // don't rehook events here, because the MobileFormatter has
389 // created new objects and so the lists will auto-subscribe
390 // the events
392 }
393
394 #endregion
395
396 #region Child Change Notification
397
398 [NonSerialized]
399 [NotUndoable]
400 private EventHandler<Csla.Core.ChildChangedEventArgs> _childChangedHandlers;
401
405 public event EventHandler<Csla.Core.ChildChangedEventArgs> ChildChanged
406 {
407 add
408 {
409 _childChangedHandlers = (EventHandler<Csla.Core.ChildChangedEventArgs>)
410 System.Delegate.Combine(_childChangedHandlers, value);
411 }
412 remove
413 {
414 _childChangedHandlers = (EventHandler<Csla.Core.ChildChangedEventArgs>)
415 System.Delegate.Remove(_childChangedHandlers, value);
416 }
417 }
418
426 [EditorBrowsable(EditorBrowsableState.Advanced)]
427 protected virtual void OnChildChanged(ChildChangedEventArgs e)
428 {
429 if (_childChangedHandlers != null)
430 _childChangedHandlers.Invoke(this, e);
431 }
432
436 private void RaiseChildChanged(
437 object childObject, PropertyChangedEventArgs propertyArgs, NotifyCollectionChangedEventArgs listArgs)
438 {
439 ChildChangedEventArgs args = new ChildChangedEventArgs(childObject, propertyArgs, listArgs);
440 OnChildChanged(args);
441 }
442
450 [EditorBrowsable(EditorBrowsableState.Never)]
451 protected virtual void Child_PropertyChanged(object sender, PropertyChangedEventArgs e)
452 {
453 // Issue 813
454 // MetaPropertyHasChanged calls in OnChildChanged we're leading to exponential growth in OnChildChanged calls
455 // Those notifications are for the UI. Ignore them in the parent
457 {
458 RaiseChildChanged(sender, e, null);
459 }
460 }
461
467 private void Child_Changed(object sender, ChildChangedEventArgs e)
468 {
469 RaiseChildChanged(e.ChildObject, e.PropertyChangedArgs, e.CollectionChangedArgs);
470 }
471
472 #endregion
473
474 #region AddNewCore
475
476 [NotUndoable]
477 [NonSerialized]
478 private EventHandler<AddedNewEventArgs<T>> _addedNewHandlers = null;
479
480 private bool _allowEdit;
481 private bool _allowNew;
482 private bool _allowRemove;
483
488 public event EventHandler<AddedNewEventArgs<T>> AddedNew
489 {
490 add
491 {
492 _addedNewHandlers = (EventHandler<AddedNewEventArgs<T>>)
493 System.Delegate.Combine(_addedNewHandlers, value);
494 }
495 remove
496 {
497 _addedNewHandlers = (EventHandler<AddedNewEventArgs<T>>)
498 System.Delegate.Remove(_addedNewHandlers, value);
499 }
500 }
501
506 [EditorBrowsable(EditorBrowsableState.Advanced)]
507 public virtual void OnAddedNew(T item)
508 {
509 if (_addedNewHandlers != null)
510 {
511 var args = new AddedNewEventArgs<T>(item);
512 _addedNewHandlers(this, args);
513 }
514 }
515
516#if (ANDROID || IOS) || NETFX_CORE
521 protected virtual void AddNewCore()
522 {
523 throw new NotImplementedException(Resources.AddNewCoreMustBeOverriden);
524 }
525#else
530 protected virtual T AddNewCore()
531 {
532 throw new NotImplementedException(Resources.AddNewCoreMustBeOverriden);
533 }
534#endif
535
536 #endregion
537
538 #region OnCollectionChanged
539
544 [EditorBrowsable(EditorBrowsableState.Advanced)]
545 protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
546 {
548 base.OnCollectionChanged(e);
549 }
550
551 #endregion
552
553 #region MobileObject
554
560 [EditorBrowsable(EditorBrowsableState.Advanced)]
561 protected override void OnGetState(SerializationInfo info)
562 {
563 base.OnGetState(info);
564 info.AddValue("Csla.Core.MobileList.AllowEdit", AllowEdit);
565 info.AddValue("Csla.Core.MobileList.AllowNew", AllowNew);
566 info.AddValue("Csla.Core.MobileList.AllowRemove", AllowRemove);
567 info.AddValue("Csla.Core.MobileList.RaiseListChangedEvents", RaiseListChangedEvents);
568 info.AddValue("Csla.Core.MobileList._supportsChangeNotificationCore", _supportsChangeNotificationCore);
569 }
570
576 [EditorBrowsable(EditorBrowsableState.Advanced)]
577 protected override void OnSetState(SerializationInfo info)
578 {
579 base.OnSetState(info);
580 AllowEdit = info.GetValue<bool>("Csla.Core.MobileList.AllowEdit");
581 AllowNew = info.GetValue<bool>("Csla.Core.MobileList.AllowNew");
582 AllowRemove = info.GetValue<bool>("Csla.Core.MobileList.AllowRemove");
583 RaiseListChangedEvents = info.GetValue<bool>("Csla.Core.MobileList.RaiseListChangedEvents");
584 _supportsChangeNotificationCore = info.GetValue<bool>("Csla.Core.MobileList._supportsChangeNotificationCore");
585 }
586
587 #endregion
588
589 #region SuppressLListChanged
590
595 public IDisposable SuppressListChangedEvents
596 {
597 get { return new SuppressListChangedEventsClass<T>(this); }
598 }
599
605 class SuppressListChangedEventsClass<TC> : IDisposable
606 {
607 private readonly ObservableBindingList<TC> _businessObject;
608 private readonly bool _initialRaiseListChangedEvents;
609
610 public SuppressListChangedEventsClass(ObservableBindingList<TC> businessObject)
611 {
612 this._businessObject = businessObject;
613 _initialRaiseListChangedEvents = businessObject.RaiseListChangedEvents;
614 businessObject.RaiseListChangedEvents = false;
615 }
616
617 public void Dispose()
618 {
619 _businessObject.RaiseListChangedEvents = _initialRaiseListChangedEvents;
620 }
621 }
622
623 #endregion
624
625 [NonSerialized]
626 [NotUndoable]
627 private Stack<bool> _oldRLCE;
628
633 protected override void SetLoadListMode(bool enabled)
634 {
635 if (_oldRLCE == null)
636 _oldRLCE = new Stack<bool>();
637 if (enabled)
638 {
639 _oldRLCE.Push(_raiseListChangedEvents);
640 _raiseListChangedEvents = false;
641 }
642 else
643 {
644 if (_oldRLCE.Count > 0)
645 _raiseListChangedEvents = _oldRLCE.Pop();
646 }
647 }
648 }
649}
Object containing information about a newly added object.
Event arguments for the BusyChanged event.
Contains event data about the changed child object.
PropertyChangedEventArgs PropertyChangedArgs
Gets the PropertyChangedEventArgs object from the child's PropertyChanged event, if the child is not ...
object ChildObject
Gets a reference to the changed child object.
NotifyCollectionChangedEventArgs CollectionChangedArgs
Gets the NotifyCollectionChangedEventArgs object from the child's CollectionChanged event,...
Event arguments for an unhandled async exception.
Inherit from this base class to easily create a serializable list class.
Extends ObservableCollection with behaviors required by CSLA .NET collections.
virtual bool IsBusy
Gets the busy status for this object and its child objects.
bool AllowRemove
Gets or sets a value indicating whether data binding can automatically remove items from this collect...
void OnBusyChanged(string propertyName, bool busy)
Raises the BusyChanged event for a specific property.
override void OnGetState(SerializationInfo info)
Override this method to get custom field values from the serialization stream.
override void RemoveItem(int index)
Remove the item at the specified index.
bool AllowEdit
Gets or sets a value indicating whether data binding can automatically edit items in this collection.
EventHandler< AddedNewEventArgs< T > > AddedNew
Event raised when a new object has been added to the collection.
override void OnSetState(SerializationInfo info)
Override this method to set custom field values into the serialization stream.
IDisposable SuppressListChangedEvents
Use this object to suppress ListChangedEvents for an entire code block.
virtual void OnRemoveEventHooks(T item)
Method invoked when events are unhooked for a child object.
virtual void OnAddEventHooks(T item)
Method invoked when events are hooked for a child object.
virtual bool IsSelfBusy
Gets the busy status for this object.
BusyChangedEventHandler BusyChanged
Event indicating that the busy status of the object has changed.
void OnUnhandledAsyncException(object originalSender, Exception error)
Raises the UnhandledAsyncException event.
virtual void OnBusyChanged(BusyChangedEventArgs args)
Override this method to be notified when the IsBusy property has changed.
virtual void OnChildChanged(ChildChangedEventArgs e)
Raises the ChildChanged event, indicating that a child object has been changed.
virtual bool SupportsChangeNotificationCore
Gets a value indicating whether this object supports change notification.
virtual void OnDeserialized()
This method is called on a newly deserialized object after deserialization is complete.
bool AllowNew
Gets or sets a value indicating whether data binding can automatically add new items to this collecti...
virtual T AddNewCore()
Override this method to create a new object that is added to the collection.
virtual void Child_PropertyChanged(object sender, PropertyChangedEventArgs e)
Handles any PropertyChanged event from a child object and echoes it up as a ChildChanged event.
override void InsertItem(int index, T item)
Invoked when an item is inserted into the list.
override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
Raises the CollectionChanged event.
virtual void OnAddedNew(T item)
Raises the AddedNew event.
void AddRange(System.Collections.Generic.IEnumerable< T > range)
Add a range of items to the list.
override void SetLoadListMode(bool enabled)
Sets the load list mode for the list
virtual void OnUnhandledAsyncException(ErrorEventArgs error)
Method invoked when an unhandled async exception has occurred.
void OnRemovingItem(T removedItem)
Raise the RemovingItem event.
T AddNew()
Adds a new item to this collection.
EventHandler< Csla.Core.ChildChangedEventArgs > ChildChanged
Event raised when a child object has been changed.
EventHandler< RemovingItemEventArgs > RemovingItem
Implements a serialization-safe RemovingItem event.
EventHandler< ErrorEventArgs > UnhandledAsyncException
Event indicating that an exception occurred during an async operation.
bool RaiseListChangedEvents
Gets or sets a value indicating whether the collection should raise changed events.
Contains event data for the RemovingItem event.
A strongly-typed resource class, for looking up localized strings, etc.
static string AddNewCoreMustBeOverriden
Looks up a localized string similar to AddNewCore must be overridden.
Object containing the serialization data for a specific object.
void AddValue(string name, object value)
Adds a value to the serialization stream.
Interface defining an object that notifies when it is busy executing an asynchronous operation.
Definition: INotifyBusy.cs:17
BusyChangedEventHandler BusyChanged
Event raised when the object's busy status changes.
Definition: INotifyBusy.cs:22
Implemented by classes that notify when a child object has changed.
EventHandler< ChildChangedEventArgs > ChildChanged
Event indictating that a child object has changed.
Implemented by an object that perfoms asynchronous operations that may raise exceptions.
EventHandler< ErrorEventArgs > UnhandledAsyncException
Event indicating that an exception occurred during an asynchronous operation.
Defines additional elements for an ObservableCollection as required by CSLA .NET.
object AddNew()
Creates and adds a new item to the collection.
Interface defining callback methods used by the SerializationFormatterFactory.GetFormatter().
void Deserialized()
Method called on an object after deserialization is complete.
delegate void BusyChangedEventHandler(object sender, BusyChangedEventArgs e)
Delegate for handling the BusyChanged event.
@ Serializable
Prevents updating or inserting until the transaction is complete.