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.
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
53 {
58 {
59 InitializeIdentity();
60 Initialize();
61 AllowNew = true;
62 }
63
67 protected ApplicationContext ApplicationContext { get; private set; }
69
70 #region Initialize
71
77 protected virtual void Initialize()
78 { /* allows subclass to initialize events before any other activity occurs */ }
79
80 #endregion
81
82 #region Identity
83
84 private int _identity = -1;
85
87 {
88 get { return _identity; }
89 }
90
91 private void InitializeIdentity()
92 {
93 _identity = ((IParent)this).GetNextIdentity(_identity);
94 }
95
96 [NonSerialized]
97 [NotUndoable]
98 private IdentityManager _identityManager;
99
100 int IParent.GetNextIdentity(int current)
101 {
102 var me = (IParent)this;
103 if (me.Parent != null)
104 {
105 return me.Parent.GetNextIdentity(current);
106 }
107 else
108 {
109 if (_identityManager == null)
110 _identityManager = new IdentityManager();
111 return _identityManager.GetNextIdentity(current);
112 }
113 }
114
115 #endregion
116
117 #region SaveItem Methods
118
122 public event EventHandler<Csla.Core.SavedEventArgs> Saved;
123
131 [EditorBrowsable(EditorBrowsableState.Advanced)]
132 protected virtual void OnSaved(T newObject, Exception error)
133 {
134 if (Saved != null)
135 Saved(this, new SavedEventArgs(newObject, error, null));
136 }
137
142 public async Task SaveItemAsync(T item)
143 {
144 await SaveItemAsync(IndexOf(item));
145 }
146
151 public async Task SaveItemAsync(int index)
152 {
153 await SaveItemAsync(index, false);
154 }
155
161 protected virtual async Task SaveItemAsync(int index, bool delete)
162 {
163 T item = this[index];
164 var handleBusy = false;
165 if ((item.IsDeleted || delete) || (item.IsValid && item.IsDirty))
166 {
167 T savable = item;
168
169 // attempt to clone object
170 ICloneable cloneable = savable as ICloneable;
171 if (cloneable != null)
172 {
173 savable = (T)cloneable.Clone();
174 MethodCaller.CallMethodIfImplemented(item, "MarkBusy");
175 handleBusy = true;
176 }
177
178 // commit all changes
179 int editLevel = savable.EditLevel;
180 for (int tmp = 1; tmp <= editLevel; tmp++)
181 savable.AcceptChanges(editLevel - tmp, false);
182
183 if (delete)
184 savable.Delete();
185
186 Exception error = null;
187 T result = default(T);
189 try
190 {
191 result = await dp.UpdateAsync((T)savable);
192 }
193 catch (AggregateException ex)
194 {
195 if (ex.InnerExceptions.Count > 0)
196 error = ex.InnerExceptions[0];
197 else
198 error = ex;
199 }
200 catch (Exception ex)
201 {
202 error = ex;
203 }
204 finally
205 {
206 if (handleBusy)
207 MethodCaller.CallMethodIfImplemented(item, "MarkIdle");
208 }
209 // update index - this may have changed under the duration of async call
210 index = IndexOf(item);
211 if (error == null && result != null)
212 {
213 if (savable.IsDeleted)
214 {
215 //SafeRemoveItem will raise INotifyCollectionChanged event
216 SafeRemoveItem(index);
217 }
218 else
219 {
220 for (int tmp = 1; tmp <= editLevel; tmp++)
221 result.CopyState(tmp, false);
222
223 SafeSetItem(index, result);
224 OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, index));
225 OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, this[index], index));
226 }
227 item.SaveComplete(result);
228 OnSaved(result, null);
229 }
230 else
231 {
232 item.SaveComplete(item);
233 OnSaved(item, error);
234 }
235 }
236 }
237
250 public void SaveItem(T item)
251 {
252 SaveItem(IndexOf(item));
253 }
254
267 public async void SaveItem(int index)
268 {
269 try
270 {
271 await SaveItemAsync(index);
272 }
273 catch (AggregateException ex)
274 {
275 if (ex.InnerExceptions.Count > 0)
276 throw ex.InnerExceptions[0];
277 else
278 throw;
279 }
280 }
281
282 private void SafeSetItem(int index, T newObject)
283 {
284 //This is needed because we cannot call base.SetItem from lambda expression
285 this[index].SetParent(null);
286 base.OnRemoveEventHooks(this[index]);
287 newObject.SetParent(this);
288 base.SetItem(index, newObject);
289 base.OnAddEventHooks(newObject);
290 }
291
292 private void SafeRemoveItem(int index)
293 {
294 this[index].SetParent(null);
295 base.OnRemoveEventHooks(this[index]);
296 base.RemoveItem(index);
297 }
298
299 #endregion
300
301 #region Insert, Remove, Clear
302
307 protected override T AddNewCore()
308 {
310 T item = dp.Create();
311 Add(item);
312 return item;
313 }
314
321 protected override void InsertItem(int index, T item)
322 {
323 item.SetParent(this);
324 base.InsertItem(index, item);
325 }
326
332 protected override async void RemoveItem(int index)
333 {
334 T item = this[index];
335 if (item.IsDeleted == false)
336 {
337 // only delete/save the item if it is not new
338 if (!item.IsNew)
339 {
340 try
341 {
342 await SaveItemAsync(index, true);
343 }
344 catch (AggregateException ex)
345 {
346 if (ex.InnerExceptions.Count > 0)
347 throw ex.InnerExceptions[0];
348 else
349 throw;
350 }
351 }
352 else
353 {
354 SafeRemoveItem(index);
355 OnSaved(item, null);
356 }
357 }
358 }
359
366 protected override void SetItem(int index, T item)
367 {
368 item.SetParent(this);
369 base.SetItem(index, item);
370 }
371
372 #endregion
373
374 #region IParent Members
375
387 protected bool RaiseReplaceEvents { get; set; }
388
393 protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
394 {
395 // SL Data Grid's DataGridDataConnection object does not support replace action.
396 // It throws an excpetioon when this occurs.
397 if (this.RaiseListChangedEvents && (e.Action != NotifyCollectionChangedAction.Replace || RaiseReplaceEvents))
398 base.OnCollectionChanged(e);
399 }
400
405 protected override bool SupportsChangeNotificationCore
406 {
407 get
408 {
409 return true;
410 }
411 }
412
413 void Csla.Core.IParent.ApplyEditChild(Core.IEditableBusinessObject child)
414 {
415 if (child.EditLevel == 0)
416 SaveItem((T)child);
417 }
418
419 void Csla.Core.IParent.RemoveChild(Core.IEditableBusinessObject child)
420 {
421 // do nothing, removal of a child is handled by
422 // the RemoveItem override
423 }
424
425
427 {
428 get { return null; }
429 }
430
431 #endregion
432
433 #region IsBusy
434
440 public override bool IsBusy
441 {
442 get
443 {
444 // run through all the child objects
445 // and if any are dirty then then
446 // collection is dirty
447 foreach (T child in this)
448 if (child.IsBusy)
449 return true;
450
451 return false;
452 }
453 }
454 #endregion
455
456 #region Serialization Notification
457
461 [EditorBrowsable(EditorBrowsableState.Advanced)]
462 protected override void OnDeserialized()
463 {
464 foreach (IEditableBusinessObject child in this)
465 child.SetParent(this);
466
467 base.OnDeserialized();
468 }
469
470 #endregion
471
472 #region Data Access
473
474 private void DataPortal_Update()
475 {
476 throw new NotSupportedException(Properties.Resources.UpdateNotSupportedException);
477 }
478
479 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "criteria")]
480 [Delete]
481 private void DataPortal_Delete(object criteria)
482 {
483 throw new NotSupportedException(Properties.Resources.DeleteNotSupportedException);
484 }
485
491 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member"), EditorBrowsable(EditorBrowsableState.Advanced)]
493 {
494
495 }
496
502 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member"), EditorBrowsable(EditorBrowsableState.Advanced)]
504 {
505
506 }
507
514 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member"), EditorBrowsable(EditorBrowsableState.Advanced)]
515 protected virtual void DataPortal_OnDataPortalException(DataPortalEventArgs e, Exception ex)
516 {
517
518 }
519
520 #endregion
521
522 #region ToArray
523
527 public T[] ToArray()
528 {
529 List<T> result = new List<T>();
530 foreach (T item in this)
531 result.Add(item);
532 return result.ToArray();
533 }
534
535 #endregion
536
537 #region IDataPortalTarget Members
538
539 void Csla.Server.IDataPortalTarget.CheckRules()
540 { }
541
542 void Csla.Server.IDataPortalTarget.MarkAsChild()
543 { }
544
545 void Csla.Server.IDataPortalTarget.MarkNew()
546 { }
547
548 void Csla.Server.IDataPortalTarget.MarkOld()
549 { }
550
551 void Csla.Server.IDataPortalTarget.DataPortal_OnDataPortalInvoke(DataPortalEventArgs e)
552 {
554 }
555
556 void Csla.Server.IDataPortalTarget.DataPortal_OnDataPortalInvokeComplete(DataPortalEventArgs e)
557 {
559 }
560
561 void Csla.Server.IDataPortalTarget.DataPortal_OnDataPortalException(DataPortalEventArgs e, Exception ex)
562 {
564 }
565
566 void Csla.Server.IDataPortalTarget.Child_OnDataPortalInvoke(DataPortalEventArgs e)
567 { }
568
569 void Csla.Server.IDataPortalTarget.Child_OnDataPortalInvokeComplete(DataPortalEventArgs e)
570 { }
571
572 void Csla.Server.IDataPortalTarget.Child_OnDataPortalException(DataPortalEventArgs e, Exception ex)
573 { }
574
575 #endregion
576
577 #region Mobile object overrides
578
586 protected override void OnGetState(SerializationInfo info)
587 {
588 info.AddValue("Csla.Core.BusinessBase._identity", _identity);
589 base.OnGetState(info);
590 }
591
599 protected override void OnSetState(SerializationInfo info)
600 {
601 _identity = info.GetValue<int>("Csla.Core.BusinessBase._identity");
602 base.OnSetState(info);
603 }
604
605 #endregion
606 }
607}
Provides consistent context information between the client and server DataPortal objects.
object CreateInstanceDI(Type objectType, params object[] parameters)
Creates an object using 'Activator.CreateInstance' using service provider (if one is available) to po...
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...
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.
Client side data portal used for making asynchronous data portal calls in .NET.
Definition: DataPortalT.cs:24
T Create(params object[] criteria)
Called by a factory method in a business class to create a new object, which is loaded with default v...
Definition: DataPortalT.cs:151
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:487
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 type.
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.
ApplicationContext ApplicationContext
Gets the current ApplicationContext
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.
Implement if a class requires access to the CSLA ApplicationContext type.
ApplicationContext ApplicationContext
Gets or sets the current ApplicationContext object.
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.