CSLA.NET 5.4.2
CSLA .NET is a software development framework that helps you build a reusable, maintainable object-oriented business layer for your app.
DynamicListBase.cs
Go to the documentation of this file.
1//-----------------------------------------------------------------------
2// <copyright file="DynamicListBase.cs" company="Marimer LLC">
3// Copyright (c) Marimer LLC. All rights reserved.
4// Website: https://cslanet.com
5// </copyright>
6// <summary>This is the base class from which collections</summary>
7//-----------------------------------------------------------------------
8using System;
9using System.Collections.Generic;
10using System.Collections.Specialized;
11using System.ComponentModel;
12using System.Threading.Tasks;
13using Csla.Core;
14using Csla.Reflection;
16
17namespace Csla
18{
44 [Serializable()]
45 public abstract class DynamicListBase<T> :
46#if (ANDROID || IOS) || NETFX_CORE
48#else
50#endif
51 Core.IParent, Csla.Server.IDataPortalTarget, ISerializationNotification, IBusinessObject
53 {
58 {
59 InitializeIdentity();
60 Initialize();
61 AllowNew = true;
62 }
63
64 #region Initialize
65
71 protected virtual void Initialize()
72 { /* allows subclass to initialize events before any other activity occurs */ }
73
74 #endregion
75
76 #region Identity
77
78 private int _identity = -1;
79
81 {
82 get { return _identity; }
83 }
84
85 private void InitializeIdentity()
86 {
87 _identity = ((IParent)this).GetNextIdentity(_identity);
88 }
89
90 [NonSerialized]
91 [NotUndoable]
92 private IdentityManager _identityManager;
93
94 int IParent.GetNextIdentity(int current)
95 {
96 var me = (IParent)this;
97 if (me.Parent != null)
98 {
99 return me.Parent.GetNextIdentity(current);
100 }
101 else
102 {
103 if (_identityManager == null)
104 _identityManager = new IdentityManager();
105 return _identityManager.GetNextIdentity(current);
106 }
107 }
108
109 #endregion
110
111 #region SaveItem Methods
112
116 public event EventHandler<Csla.Core.SavedEventArgs> Saved;
117
125 [EditorBrowsable(EditorBrowsableState.Advanced)]
126 protected virtual void OnSaved(T newObject, Exception error)
127 {
128 if (Saved != null)
129 Saved(this, new SavedEventArgs(newObject, error, null));
130 }
131
136 public async Task SaveItemAsync(T item)
137 {
138 await SaveItemAsync(IndexOf(item));
139 }
140
145 public async Task SaveItemAsync(int index)
146 {
147 await SaveItemAsync(index, false);
148 }
149
155 protected virtual async Task SaveItemAsync(int index, bool delete)
156 {
157 T item = this[index];
158 var handleBusy = false;
159 if ((item.IsDeleted || delete) || (item.IsValid && item.IsDirty))
160 {
161 T savable = item;
162
163 // attempt to clone object
164 ICloneable cloneable = savable as ICloneable;
165 if (cloneable != null)
166 {
167 savable = (T)cloneable.Clone();
168 MethodCaller.CallMethodIfImplemented(item, "MarkBusy");
169 handleBusy = true;
170 }
171
172 // commit all changes
173 int editLevel = savable.EditLevel;
174 for (int tmp = 1; tmp <= editLevel; tmp++)
175 savable.AcceptChanges(editLevel - tmp, false);
176
177 if (delete)
178 savable.Delete();
179
180 Exception error = null;
181 T result = default(T);
182 try
183 {
184 result = await DataPortal.UpdateAsync<T>((T)savable);
185 }
186 catch (AggregateException ex)
187 {
188 if (ex.InnerExceptions.Count > 0)
189 error = ex.InnerExceptions[0];
190 else
191 error = ex;
192 }
193 catch (Exception ex)
194 {
195 error = ex;
196 }
197 finally
198 {
199 if (handleBusy)
200 MethodCaller.CallMethodIfImplemented(item, "MarkIdle");
201 }
202 // update index - this may have changed under the duration of async call
203 index = IndexOf(item);
204 if (error == null && result != null)
205 {
206 if (savable.IsDeleted)
207 {
208 //SafeRemoveItem will raise INotifyCollectionChanged event
209 SafeRemoveItem(index);
210 }
211 else
212 {
213 for (int tmp = 1; tmp <= editLevel; tmp++)
214 result.CopyState(tmp, false);
215
216 SafeSetItem(index, result);
217 OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, index));
218 OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, this[index], index));
219 }
220 item.SaveComplete(result);
221 OnSaved(result, null);
222 }
223 else
224 {
225 item.SaveComplete(item);
226 OnSaved(item, error);
227 }
228 }
229 }
230
243 public void SaveItem(T item)
244 {
245 SaveItem(IndexOf(item));
246 }
247
260 public async void SaveItem(int index)
261 {
262 try
263 {
264 await SaveItemAsync(index);
265 }
266 catch (AggregateException ex)
267 {
268 if (ex.InnerExceptions.Count > 0)
269 throw ex.InnerExceptions[0];
270 else
271 throw;
272 }
273 }
274
275 private void SafeSetItem(int index, T newObject)
276 {
277 //This is needed because we cannot call base.SetItem from lambda expression
278 this[index].SetParent(null);
279 base.OnRemoveEventHooks(this[index]);
280 newObject.SetParent(this);
281 base.SetItem(index, newObject);
282 base.OnAddEventHooks(newObject);
283 }
284
285 private void SafeRemoveItem(int index)
286 {
287 this[index].SetParent(null);
288 base.OnRemoveEventHooks(this[index]);
289 base.RemoveItem(index);
290 }
291
292 #endregion
293
294 #region Insert, Remove, Clear
295
296#if NETFX_CORE || (ANDROID || IOS)
302 protected override void AddNewCore()
303 {
304 var portal = new Csla.DataPortal<T>();
305 portal.CreateCompleted += (o, e) =>
306 {
307 // call OnUnhandledAsyncException if failed
308 if (e.Error != null)
309 {
310 OnUnhandledAsyncException(new ErrorEventArgs(this, e.Error));
311 }
312 else
313 {
314 try
315 {
316 this.Add(e.Object);
317 OnAddedNew(e.Object);
318 }
319 catch (Exception ex)
320 {
322 }
323 }
324 };
325
326 portal.BeginCreate();
327 }
328#else
333 protected override T AddNewCore()
334 {
335 T item = Csla.DataPortal.Create<T>();
336 Add(item);
337 return item;
338 }
339#endif
340
347 protected override void InsertItem(int index, T item)
348 {
349 item.SetParent(this);
350 base.InsertItem(index, item);
351 }
352
358 protected override async void RemoveItem(int index)
359 {
360 T item = this[index];
361 if (item.IsDeleted == false)
362 {
363 // only delete/save the item if it is not new
364 if (!item.IsNew)
365 {
366 try
367 {
368 await SaveItemAsync(index, true);
369 }
370 catch (AggregateException ex)
371 {
372 if (ex.InnerExceptions.Count > 0)
373 throw ex.InnerExceptions[0];
374 else
375 throw;
376 }
377 }
378 else
379 {
380 SafeRemoveItem(index);
381 OnSaved(item, null);
382 }
383 }
384 }
385
392 protected override void SetItem(int index, T item)
393 {
394 item.SetParent(this);
395 base.SetItem(index, item);
396 }
397
398 #endregion
399
400 #region IParent Members
401
413 protected bool RaiseReplaceEvents { get; set; }
414
419 protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
420 {
421 // SL Data Grid's DataGridDataConnection object does not support replace action.
422 // It throws an excpetioon when this occurs.
423 if (this.RaiseListChangedEvents && (e.Action != NotifyCollectionChangedAction.Replace || RaiseReplaceEvents))
424 base.OnCollectionChanged(e);
425 }
426
431 protected override bool SupportsChangeNotificationCore
432 {
433 get
434 {
435 return true;
436 }
437 }
438
439 void Csla.Core.IParent.ApplyEditChild(Core.IEditableBusinessObject child)
440 {
441 if (child.EditLevel == 0)
442 SaveItem((T)child);
443 }
444
445 void Csla.Core.IParent.RemoveChild(Core.IEditableBusinessObject child)
446 {
447 // do nothing, removal of a child is handled by
448 // the RemoveItem override
449 }
450
451
453 {
454 get { return null; }
455 }
456
457 #endregion
458
459 #region IsBusy
460
466 public override bool IsBusy
467 {
468 get
469 {
470 // run through all the child objects
471 // and if any are dirty then then
472 // collection is dirty
473 foreach (T child in this)
474 if (child.IsBusy)
475 return true;
476
477 return false;
478 }
479 }
480 #endregion
481
482 #region Serialization Notification
483
487 [EditorBrowsable(EditorBrowsableState.Advanced)]
488 protected override void OnDeserialized()
489 {
490 foreach (IEditableBusinessObject child in this)
491 child.SetParent(this);
492
493 base.OnDeserialized();
494 }
495
496 #endregion
497
498 #region Data Access
499
500 private void DataPortal_Update()
501 {
502 throw new NotSupportedException(Properties.Resources.UpdateNotSupportedException);
503 }
504
505 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "criteria")]
506 [Delete]
507 private void DataPortal_Delete(object criteria)
508 {
509 throw new NotSupportedException(Properties.Resources.DeleteNotSupportedException);
510 }
511
517 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member"), EditorBrowsable(EditorBrowsableState.Advanced)]
519 {
520
521 }
522
528 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member"), EditorBrowsable(EditorBrowsableState.Advanced)]
530 {
531
532 }
533
540 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member"), EditorBrowsable(EditorBrowsableState.Advanced)]
541 protected virtual void DataPortal_OnDataPortalException(DataPortalEventArgs e, Exception ex)
542 {
543
544 }
545
546 #endregion
547
548 #region ToArray
549
553 public T[] ToArray()
554 {
555 List<T> result = new List<T>();
556 foreach (T item in this)
557 result.Add(item);
558 return result.ToArray();
559 }
560
561 #endregion
562
563 #region IDataPortalTarget Members
564
565 void Csla.Server.IDataPortalTarget.CheckRules()
566 { }
567
568 void Csla.Server.IDataPortalTarget.MarkAsChild()
569 { }
570
571 void Csla.Server.IDataPortalTarget.MarkNew()
572 { }
573
574 void Csla.Server.IDataPortalTarget.MarkOld()
575 { }
576
577 void Csla.Server.IDataPortalTarget.DataPortal_OnDataPortalInvoke(DataPortalEventArgs e)
578 {
580 }
581
582 void Csla.Server.IDataPortalTarget.DataPortal_OnDataPortalInvokeComplete(DataPortalEventArgs e)
583 {
585 }
586
587 void Csla.Server.IDataPortalTarget.DataPortal_OnDataPortalException(DataPortalEventArgs e, Exception ex)
588 {
590 }
591
592 void Csla.Server.IDataPortalTarget.Child_OnDataPortalInvoke(DataPortalEventArgs e)
593 { }
594
595 void Csla.Server.IDataPortalTarget.Child_OnDataPortalInvokeComplete(DataPortalEventArgs e)
596 { }
597
598 void Csla.Server.IDataPortalTarget.Child_OnDataPortalException(DataPortalEventArgs e, Exception ex)
599 { }
600
601 #endregion
602
603 #region Mobile object overrides
604
612 protected override void OnGetState(SerializationInfo info)
613 {
614 info.AddValue("Csla.Core.BusinessBase._identity", _identity);
615 base.OnGetState(info);
616 }
617
625 protected override void OnSetState(SerializationInfo info)
626 {
627 _identity = info.GetValue<int>("Csla.Core.BusinessBase._identity");
628 base.OnSetState(info);
629 }
630
631 #endregion
632 }
633}
Event arguments for an unhandled async exception.
Extends BindingList of T by adding extra behaviors.
Used by the root object in a graph to manage the object instance identity values for the graph.
int GetNextIdentity(int current)
Gets and consumes the next available unique identity value for an object instance in the object graph...
Extends ObservableCollection with behaviors required by CSLA .NET collections.
bool AllowNew
Gets or sets a value indicating whether data binding can automatically add new items to this collecti...
virtual void OnAddedNew(T item)
Raises the AddedNew event.
virtual void OnUnhandledAsyncException(ErrorEventArgs error)
Method invoked when an unhandled async exception has occurred.
bool RaiseListChangedEvents
Gets or sets a value indicating whether the collection should raise changed events.
Event arguments containing a reference to the new object that was returned as a result of the Save() ...
Provides information about the DataPortal call.
This is the client-side DataPortal.
Definition: DataPortalT.cs:24
async Task< T > UpdateAsync(T obj)
Called by a factory method in a business class or by the UI to update an object.
Definition: DataPortalT.cs:773
EventHandler< DataPortalResult< T > > CreateCompleted
Event raised when the operation has completed.
Definition: DataPortalT.cs:192
static object Create(Type objectType, object criteria)
Called by a factory method in a business class to create a new object, which is loaded with default v...
Definition: DataPortal.cs:91
This is the base class from which collections of editable root business objects should be derived.
override void SetItem(int index, T item)
Replaces item in the list.
override void OnGetState(SerializationInfo info)
Override this method to insert your field values into the MobileFormatter serialzation stream.
DynamicListBase()
Creates an instance of the object.
async Task SaveItemAsync(int index)
Saves the specified item in the list.
override bool SupportsChangeNotificationCore
Gets a value indicating whether this collection supports change notification (always returns true).
override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
Raises the CollectionChanged event.
async void SaveItem(int index)
Saves the specified item in the list.
EventHandler< Csla.Core.SavedEventArgs > Saved
Event raised when an object in the list has been saved.
void SaveItem(T item)
Saves the specified item in the list.
T[] ToArray()
Get an array containing all items in the list.
override void OnDeserialized()
Set parent reference.
virtual async Task SaveItemAsync(int index, bool delete)
Saves the specified item in the list.
virtual void DataPortal_OnDataPortalException(DataPortalEventArgs e, Exception ex)
Called by the server-side DataPortal if an exception occurs during data access.
async Task SaveItemAsync(T item)
Saves the specified item in the list.
override T AddNewCore()
Adds a new item to the list.
override async void RemoveItem(int index)
Removes an item from the list.
virtual void DataPortal_OnDataPortalInvokeComplete(DataPortalEventArgs e)
Called by the server-side DataPortal after calling the requested DataPortal_xyz method.
bool RaiseReplaceEvents
Gets or sets a value indicating whether the Replace event should be raised when OnCollectionChanged()...
override bool IsBusy
Gets a value indicating whether this object or any child object is currently executing an async opera...
virtual void Initialize()
Override this method to set up event handlers so user code in a partial class can respond to events r...
virtual void DataPortal_OnDataPortalInvoke(DataPortalEventArgs e)
Called by the server-side DataPortal prior to calling the requested DataPortal_xyz method.
override void OnSetState(SerializationInfo info)
Override this method to retrieve your field values from the MobileFormatter serialzation stream.
override void InsertItem(int index, T item)
Gives the new object a parent reference to this list.
virtual void OnSaved(T newObject, Exception error)
Raises the Saved event.
Object containing the serialization data for a specific object.
void AddValue(string name, object value)
Adds a value to the serialization stream.
This is the core interface implemented by all CSLA .NET base classes.
int Identity
Gets a value representing this object instance's unique identity value within the business object gra...
Defines the common methods required by all editable CSLA single objects.
void SetParent(IParent parent)
Used by BusinessListBase as a child object is created to tell the child object about its parent.
Defines the interface that must be implemented by any business object that contains child objects.
Definition: IParent.cs:18
int GetNextIdentity(int current)
Gets and consumes the next available unique identity value for an object instance in the object graph...
void ApplyEditChild(Core.IEditableBusinessObject child)
Override this method to be notified when a child object's Core.BusinessBase.ApplyEdit method has comp...
void RemoveChild(Core.IEditableBusinessObject child)
This method is called by a child object when it wants to be removed from the collection.
IParent Parent
Provide access to the parent reference for use in child object code.
Definition: IParent.cs:39
Specifies that the object can save itself.
Definition: ISavableT.cs:19
Defines the methods required to participate in n-level undo within the CSLA .NET framework.
Interface to be implemented by any object that supports serialization by the SerializationFormatterFa...
Interface defining callback methods used by the SerializationFormatterFactory.GetFormatter().
@ Serializable
Prevents updating or inserting until the transaction is complete.