9using System.Collections;
10using System.Collections.Generic;
11using System.Collections.Specialized;
12using System.ComponentModel;
13using System.ComponentModel.DataAnnotations;
14using System.Linq.Expressions;
15using System.Threading.Tasks;
37#if ANDROID || IOS || XAMARIN
38 public abstract class ViewModelBase<T> : INotifyPropertyChanged, IViewModel
50 SetPropertiesAtObjectLevel();
61 [Obsolete(
"Use RefreshAsync",
false)]
67 Model = await DoInitAsync();
70#pragma warning disable CA1031
76#pragma warning restore CA1031
80#pragma warning disable 1998
87 [Obsolete(
"Use RefreshAsync",
false)]
90 throw new NotImplementedException(
"DoInitAsync");
92#pragma warning restore 1998
94 private Exception _error;
101 [Display(AutoGenerateField =
false)]
102 [ScaffoldColumn(
false)]
103 [Obsolete(
"Use RefreshAsync/SaveAsync",
false)]
106 get {
return _error; }
109 if (!ReferenceEquals(_error, value))
112 OnPropertyChanged(nameof(
Error));
122 [Obsolete(
"Use RefreshAsync/SaveAsync",
false)]
130 [Obsolete(
"Use RefreshAsync/SaveAsync",
false)]
131 protected virtual void OnError(Exception error)
149 [Obsolete(
"Use RefreshAsync",
false)]
152 if (typeof(T) !=
null)
158 Model = factoryMethod.Invoke();
160#pragma warning disable CA1031
165#pragma warning restore CA1031
176 [Obsolete(
"Use RefreshAsync",
false)]
177 protected virtual void DoRefresh(
string factoryMethod, params
object[] factoryParameters)
179 if (typeof(T) !=
null)
185 Model = (T)MethodCaller.CallFactoryMethod(typeof(T), factoryMethod, factoryParameters);
187#pragma warning disable CA1031
192#pragma warning restore CA1031
202 [Obsolete(
"Use RefreshAsync",
false)]
205 DoRefresh(factoryMethod, Array.Empty<
object>());
217 [Obsolete(
"Use RefreshAsync",
false)]
220 if (typeof(T) !=
null)
226 var handler = (EventHandler<DataPortalResult<T>>)CreateHandler(typeof(T));
227 factoryMethod(handler);
229#pragma warning disable CA1031
235#pragma warning restore CA1031
244 [Obsolete(
"Use RefreshAsync",
false)]
245 protected virtual void BeginRefresh(
string factoryMethod, params
object[] factoryParameters)
247 if (typeof(T) !=
null)
252 var parameters =
new List<object>(factoryParameters)
254 CreateHandler(typeof(T))
257 MethodCaller.CallFactoryMethod(typeof(T), factoryMethod, parameters.ToArray());
259#pragma warning disable CA1031
265#pragma warning restore CA1031
273 [Obsolete(
"Use RefreshAsync",
false)]
276 BeginRefresh(factoryMethod, Array.Empty<
object>());
279 private Delegate CreateHandler(Type objectType)
281 System.Reflection.MethodInfo method = MethodCaller.GetMethod(GetType(),
"QueryCompleted");
283 var args = typeof(EventHandler<>).MakeGenericType(innerType);
285 Delegate handler = Delegate.CreateDelegate(args,
this, method);
289 [Obsolete(
"Use RefreshAsync",
false)]
290 private void QueryCompleted(
object sender, EventArgs e)
295 if (eventArgs.Error ==
null)
297 var model = (T)eventArgs.Object;
302 Error = eventArgs.Error;
316 [Obsolete(
"Use RefreshAsync",
false)]
324 [Obsolete(
"Use RefreshAsync",
false)]
332 [Obsolete(
"Use SaveAsync",
false)]
339 UnhookChangedEvents(Model);
341 if (ManageObjectLifetime)
344 if (Model is ICloneable clonable)
349 undoable.ApplyEdit();
352 result = (T)savable.
Save();
359 HookChangedEvents(Model);
370 [Obsolete(
"Use SaveAsync",
false)]
376 if (ManageObjectLifetime)
379 if (Model is ICloneable clonable)
384 undoable.ApplyEdit();
387 savable.
Saved += (o, e) =>
392 var result = e.NewObject;
393 var model = (T)result;
407#pragma warning disable CA1031
414#pragma warning restore CA1031
422 [Obsolete(
"Use SaveAsync",
false)]
431 [Obsolete(
"Use SaveAsync",
false)]
437#if ANDROID || IOS || XAMARIN || WINDOWS_UWP
444 get {
return _model; }
447 if (!ReferenceEquals(value, _model))
449 var oldValue = _model;
451 this.OnModelChanged((T)oldValue, _model);
452 OnPropertyChanged(nameof(Model));
460 public static readonly DependencyProperty ModelProperty =
462 new PropertyMetadata((o, e) =>
465 viewmodel.OnModelChanged((T)e.OldValue, (T)e.NewValue);
473 get {
return (T)GetValue(ModelProperty); }
474 set { SetValue(ModelProperty, value); }
483#if ANDROID || IOS || XAMARIN
484 public bool ManageObjectLifetimeProperty;
486 public static readonly DependencyProperty ManageObjectLifetimeProperty =
487 DependencyProperty.Register(
"ManageObjectLifetime", typeof(
bool),
496 [Display(AutoGenerateField =
false)]
497 [ScaffoldColumn(
false)]
498 public bool ManageObjectLifetime
500#if ANDROID || IOS || XAMARIN
501 get {
return (
bool)ManageObjectLifetimeProperty; }
502 set { ManageObjectLifetimeProperty = value; }
504 get {
return (
bool)GetValue(ManageObjectLifetimeProperty); }
505 set { SetValue(ManageObjectLifetimeProperty, value); }
509 private bool _isBusy;
517 get {
return _isBusy; }
520 if (value != _isBusy)
523 OnPropertyChanged(nameof(IsBusy));
529 private bool _isDirty;
535 public virtual bool IsDirty
543 if (_isDirty != value)
546 OnPropertyChanged(nameof(IsDirty));
551 private bool _isValid;
557 public virtual bool IsValid
565 if (_isValid != value)
568 OnPropertyChanged(nameof(IsValid));
573 private bool _canSave =
false;
579 public virtual bool CanSave
587 if (_canSave != value)
590 OnPropertyChanged(nameof(CanSave));
595 private bool _canCancel =
false;
601 public virtual bool CanCancel
609 if (_canCancel != value)
612 OnPropertyChanged(nameof(CanCancel));
617 private bool _canCreate =
false;
624 public virtual bool CanCreate
632 if (_canCreate != value)
635 OnPropertyChanged(nameof(CanCreate));
640 private bool _canDelete =
false;
646 public virtual bool CanDelete
654 if (_canDelete != value)
657 OnPropertyChanged(nameof(CanDelete));
662 private bool _canFetch =
false;
669 public virtual bool CanFetch
677 if (_canFetch != value)
680 OnPropertyChanged(nameof(CanFetch));
685 private bool _canRemove =
false;
691 public virtual bool CanRemove
699 if (_canRemove != value)
702 OnPropertyChanged(nameof(CanRemove));
707 private bool _canAddNew =
false;
713 public virtual bool CanAddNew
721 if (_canAddNew != value)
724 OnPropertyChanged(nameof(CanAddNew));
729 private void SetProperties()
731 bool isObjectBusy =
false;
740 IsDirty = targetObject.IsDirty;
741 IsValid = targetObject.IsValid;
742 CanSave = CanEditObject && targetObject.IsSavable && !isObjectBusy;
743 CanCancel = CanEditObject && targetObject.IsDirty && !isObjectBusy;
744 CanCreate = CanCreateObject && !targetObject.IsDirty && !isObjectBusy;
745 CanDelete = CanDeleteObject && !isObjectBusy && canDeleteInstance;
746 CanFetch = CanGetObject && !targetObject.IsDirty && !isObjectBusy;
749 if (Model is ICollection list)
751 Type itemType = Utilities.GetChildItemType(Model.GetType());
752 if (itemType ==
null)
760 list.Count > 0 && !isObjectBusy;
773 else if (Model is ICollection list)
775 Type itemType = Utilities.GetChildItemType(Model.GetType());
776 if (itemType ==
null)
784 list.Count > 0 && !isObjectBusy;
794 CanCreate = CanCreateObject;
796 CanFetch = CanGetObject && !IsBusy;
803 private bool _canCreateObject;
809 public virtual bool CanCreateObject
811 get {
return _canCreateObject; }
814 if (_canCreateObject != value)
816 _canCreateObject = value;
817 OnPropertyChanged(nameof(CanCreateObject));
822 private bool _canGetObject;
828 public virtual bool CanGetObject
830 get {
return _canGetObject; }
833 if (_canGetObject != value)
835 _canGetObject = value;
836 OnPropertyChanged(nameof(CanGetObject));
841 private bool _canEditObject;
848 public virtual bool CanEditObject
850 get {
return _canEditObject; }
853 if (_canEditObject != value)
855 _canEditObject = value;
856 OnPropertyChanged(nameof(CanEditObject));
861 private bool _canDeleteObject;
868 public virtual bool CanDeleteObject
870 get {
return _canDeleteObject; }
873 if (_canDeleteObject != value)
875 _canDeleteObject = value;
876 OnPropertyChanged(nameof(CanDeleteObject));
885 private void SetPropertiesAtObjectLevel()
887 Type sourceType = typeof(T);
903 protected virtual async Task<T> RefreshAsync<F>(Func<Task<T>> factory)
909 result = await factory.Invoke();
927 UnhookChangedEvents(Model);
929 if (ManageObjectLifetime)
932 if (Model is ICloneable clonable)
933 savable = (
ISavable)clonable.Clone();
937 undoable.ApplyEdit();
945 HookChangedEvents(Model);
957 if (ManageObjectLifetime)
961 UnhookChangedEvents(Model);
969 HookChangedEvents(Model);
976#if (ANDROID || IOS) || XAMARIN
981 protected virtual void BeginAddNew()
984 var ibl = (Model as System.ComponentModel.IBindingList);
986 var ibl = (Model as IBindingList);
1011 result = iobl.AddNew();
1016 var ibl = ((IBindingList)Model);
1017 result = ibl.AddNew();
1030 ((IList)Model).Remove(item);
1052 if (ReferenceEquals(oldValue, newValue))
return;
1054 if (ManageObjectLifetime && newValue is
ISupportUndo undo)
1058 if (oldValue !=
null)
1060 UnhookChangedEvents(oldValue);
1063 nb.BusyChanged -= Model_BusyChanged;
1067 if (newValue !=
null)
1069 HookChangedEvents(newValue);
1072 nb.BusyChanged += Model_BusyChanged;
1084 if (model is INotifyPropertyChanged npc)
1085 npc.PropertyChanged -= Model_PropertyChanged;
1088 ncc.ChildChanged -= Model_ChildChanged;
1090 if (model is INotifyCollectionChanged cc)
1091 cc.CollectionChanged -= Model_CollectionChanged;
1098 private void HookChangedEvents(T model)
1100 if (model is INotifyPropertyChanged npc)
1101 npc.PropertyChanged += Model_PropertyChanged;
1104 ncc.ChildChanged += Model_ChildChanged;
1106 if (model is INotifyCollectionChanged cc)
1107 cc.CollectionChanged += Model_CollectionChanged;
1129 private void Model_PropertyChanged(
object sender, PropertyChangedEventArgs e)
1139 private void Model_CollectionChanged(
object sender, NotifyCollectionChangedEventArgs e)
1144 object IViewModel.Model
1146 get {
return Model; }
1147 set { Model = (T)value; }
1161 PropertyChanged?.Invoke(
this,
new PropertyChangedEventArgs(propertyName));
Event arguments for the BusyChanged event.
string PropertyName
Property for which the Busy value has changed.
Contains event data about the changed child object.
DataPortalResult defines the results of DataPortal operation.
Tracks the business rules for a business object.
static bool HasPermission(AuthorizationActions action, Type objectType)
Checks per-type authorization rules.
Contains information about the error that has occurred.
Base class used to create ViewModel objects that implement their own commands/verbs/actions.
virtual void DoRemove(object item)
Removes an item from the Model (if it is a collection).
PropertyChangedEventHandler PropertyChanged
Event raised when a property changes.
virtual void OnModelChanged(T oldValue, T newValue)
Invoked when the Model changes, allowing event handlers to be unhooked from the old object and hooked...
virtual void BeginSave()
Saves the Model, first committing changes if ManagedObjectLifetime is true.
virtual void OnSetProperties()
Override this method to hook into to logic of setting properties when model is changed or edited.
virtual void DoCancel()
Cancels changes made to the model if ManagedObjectLifetime is true.
virtual void DoDelete()
Marks the Model for deletion (if it is an editable root object).
virtual void OnRefreshed()
Method called after a refresh operation has completed.
virtual void OnSaving(T model)
Method called after a save operation has completed and before Model is updated (when successful).
virtual T DoSave()
Saves the Model, first committing changes if ManagedObjectLifetime is true.
virtual void DoRefresh(Func< T > factoryMethod)
Creates or retrieves a new instance of the Model by invoking a static factory method.
virtual void OnError(Exception error)
Raises ErrorOccurred event when an error occurs during processing.
void UnhookChangedEvents(T model)
Unhooks changed event handlers from the model.
virtual void OnSaved()
Method called after a save operation has completed (whether successful or not).
async Task< ViewModelBase< T > > InitAsync()
Method used to perform async initialization of the viewmodel.
virtual void DoRefresh(string factoryMethod, params object[] factoryParameters)
Creates or retrieves a new instance of the Model by invoking a static factory method.
ViewModelBase()
Create new instance of base class used to create ViewModel objects that implement their own commands/...
virtual void BeginRefresh(Action< EventHandler< DataPortalResult< T > > > factoryMethod)
Creates or retrieves a new instance of the Model by invoking a static factory method.
EventHandler< ErrorEventArgs > ErrorOccurred
Event raised when an error occurs during processing.
virtual async Task< T > SaveAsync()
Saves the Model, first committing changes if ManagedObjectLifetime is true.
virtual void OnRefreshing(T model)
Method called after a refresh operation has completed and before the model is updated.
virtual void DoRefresh(string factoryMethod)
Creates or retrieves a new instance of the Model by invoking a static factory method.
virtual void BeginRefresh(string factoryMethod)
Creates or retrieves a new instance of the Model by invoking a static factory method.
virtual void BeginRefresh(string factoryMethod, params object[] factoryParameters)
Creates or retrieves a new instance of the Model by invoking a static factory method.
virtual object DoAddNew()
Adds a new item to the Model (if it is a collection).
virtual void OnPropertyChanged(string propertyName)
Raise the PropertyChanged event.
virtual async Task< T > DoInitAsync()
Override this method to implement async initialization of the model object.
Defines the common methods required by all editable CSLA single objects.
Interface defining an object that notifies when it is busy executing an asynchronous operation.
bool IsBusy
Gets a value indicating whether the object, or any of the object's child objects, are busy running an...
Implemented by classes that notify when a child object has changed.
Defines additional elements for an ObservableCollection as required by CSLA .NET.
Specifies that the object can save itself.
EventHandler< SavedEventArgs > Saved
Event raised when an object has been saved.
object Save()
Saves the object to the database.
Task< object > SaveAsync()
Saves the object to the database.
Define the common methods used by the UI to interact with n-level undo.
Defines the common properties required objects that track their own status.
IDataPortalResult defines the results of DataPortal operation
Defines a CSLA .NET viewmodel object.
AuthorizationActions
Authorization actions.
@ Error
Represents a serious business rule violation that should cause an object to be considered invalid.
@ PropertyChanged
Called from PropertyHasChanged event on BO but not including cascade calls by AffectedProperties