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.
Csla.Blazor/ViewModel.cs
Go to the documentation of this file.
1//-----------------------------------------------------------------------
2// <copyright file="ViewModel.cs" company="Marimer LLC">
3// Copyright (c) Marimer LLC. All rights reserved.
4// Website: https://cslanet.com
5// </copyright>
6// <summary>Base type for creating your own viewmodel</summary>
7//-----------------------------------------------------------------------
8using System;
9using System.Collections.Generic;
10using System.ComponentModel;
11using System.Linq;
12using System.Linq.Expressions;
13using System.Threading.Tasks;
14using Csla.Reflection;
15using Csla.Rules;
16
17namespace Csla.Blazor
18{
22 public class ViewModel<T>
23 {
24 private IDataPortal<T> DataPortal { get; set; }
25
29 public event Action Saved;
33 public event Action<T, T> ModelChanging;
37 public event Action ModelChanged;
42 public event PropertyChangedEventHandler ModelPropertyChanged;
43
49 protected virtual void OnModelChanging(T oldValue, T newValue)
50 {
51 _info.Clear();
52 if (oldValue is INotifyPropertyChanged oldObj)
53 oldObj.PropertyChanged -= (s, e) => OnModelPropertyChanged(e.PropertyName);
54 if (newValue is INotifyPropertyChanged newObj)
55 newObj.PropertyChanged += (s, e) => OnModelPropertyChanged(e.PropertyName);
56 ModelChanging?.Invoke(oldValue, newValue);
57 }
58
62 protected virtual void OnModelChanged()
63 {
64 ModelChanged?.Invoke();
65 }
66
71 protected virtual void OnModelPropertyChanged(string propertyName)
72 {
73 ModelPropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
74 }
75
79 public ViewModel(IDataPortal<T> dataPortal)
80 {
81 DataPortal = dataPortal;
82 }
83
88 public async Task<T> RefreshAsync(Func<Task<T>> factory)
89 {
90 Exception = null;
91 ViewModelErrorText = null;
92 try
93 {
94 Model = await factory();
95 }
96 catch (DataPortalException ex)
97 {
98 Model = default;
99 Exception = ex;
101 }
102 catch (Exception ex)
103 {
104 Model = default;
105 Exception = ex;
106 ViewModelErrorText = ex.Message;
107 }
108 return Model;
109 }
110
115 public async Task SaveAsync()
116 {
117 Exception = null;
118 ViewModelErrorText = null;
119 if (Model is Core.ITrackStatus obj && !obj.IsSavable)
120 {
122 return;
123 }
124 try
125 {
126 Model = await DoSaveAsync();
127 Saved?.Invoke();
128 }
129 catch (Exception ex)
130 {
131 Exception = ex;
132 ViewModelErrorText = ex.Message;
133 }
134 }
135
140 protected virtual async Task<T> DoSaveAsync()
141 {
142 if (Model is Core.ISavable savable)
143 {
144 var result = (T)await savable.SaveAsync();
145 if (Model is Core.IEditableBusinessObject editable)
146 new Core.GraphMerger().MergeGraph(editable, (Core.IEditableBusinessObject)result);
147 else
148 Model = result;
149 }
150 return Model;
151 }
152
153 private T _model;
157 public T Model
158 {
159 get => _model;
160 set
161 {
162 if (!ReferenceEquals(_model, value))
163 {
164 OnModelChanging(_model, value);
165 _model = value;
166 }
167 }
168 }
169
170 private readonly Dictionary<string, object> _info = new Dictionary<string, object>();
171
179 public IPropertyInfo GetPropertyInfo<P>(Expression<Func<P>> property)
180 {
181 if (property == null)
182 throw new ArgumentNullException(nameof(property));
183
184 var keyName = property.GetKey();
185 var identifier = Microsoft.AspNetCore.Components.Forms.FieldIdentifier.Create(property);
186 return GetPropertyInfo(keyName, identifier.Model, identifier.FieldName);
187 }
188
197 public IPropertyInfo GetPropertyInfo<P>(Expression<Func<P>> property, string id)
198 {
199 if (property == null)
200 throw new ArgumentNullException(nameof(property));
201
202 var keyName = property.GetKey() + $"[{id}]";
203 var identifier = Microsoft.AspNetCore.Components.Forms.FieldIdentifier.Create(property);
204 return GetPropertyInfo(keyName, identifier.Model, identifier.FieldName);
205 }
206
214 public IPropertyInfo GetPropertyInfo(string propertyName)
215 {
216 var keyName = Model.GetType().FullName + "." + propertyName;
217 return GetPropertyInfo(keyName, Model, propertyName);
218 }
219
228 public IPropertyInfo GetPropertyInfo(string propertyName, string id)
229 {
230 var keyName = Model.GetType().FullName + "." + propertyName + $"[{id}]";
231 return GetPropertyInfo(keyName, Model, propertyName);
232 }
233
234 private IPropertyInfo GetPropertyInfo(string keyName, object model, string propertyName)
235 {
236 PropertyInfo result;
237 if (_info.TryGetValue(keyName, out object temp))
238 {
239 result = (PropertyInfo)temp;
240 }
241 else
242 {
243 result = new PropertyInfo(model, propertyName);
244 _info.Add(keyName, result);
245 }
246 return result;
247 }
248
252 public string ViewModelErrorText { get; protected set; }
253
258 protected virtual string ModelErrorText
259 {
260 get
261 {
262 if (Model is IDataErrorInfo obj)
263 {
264 return obj.Error;
265 }
266 return string.Empty;
267 }
268 }
269
275 public Exception Exception { get; private set; }
276
283 public static bool CanCreateObject()
284 {
285 return BusinessRules.HasPermission(AuthorizationActions.CreateObject, typeof(T));
286 }
287
294 public static bool CanGetObject()
295 {
296 return BusinessRules.HasPermission(AuthorizationActions.GetObject, typeof(T));
297 }
298
305 public static bool CanEditObject()
306 {
307 return BusinessRules.HasPermission(AuthorizationActions.EditObject, typeof(T));
308 }
309
316 public static bool CanDeleteObject()
317 {
318 return BusinessRules.HasPermission(AuthorizationActions.DeleteObject, typeof(T));
319 }
320 }
321}
Exposes metastate for a property.
Base type for creating your own viewmodel.
Action< T, T > ModelChanging
Event raised when Model is changing
async Task SaveAsync()
Saves the Model
static bool CanDeleteObject()
Gets a value indicating whether the current user is authorized to delete an instance of the business ...
async Task< T > RefreshAsync(Func< Task< T > > factory)
Refresh the Model
string ViewModelErrorText
Gets any error text generated by refresh or save operations
virtual string ModelErrorText
Gets the first validation error message from the Model
PropertyChangedEventHandler ModelPropertyChanged
Event raised when the Model object raises its PropertyChanged event
virtual void OnModelChanged()
Raises the ModelChanged event
virtual async Task< T > DoSaveAsync()
Override to provide custom Model save behavior
IPropertyInfo GetPropertyInfo< P >(Expression< Func< P > > property)
Get a PropertyInfo object for a property.
Exception Exception
Gets the last exception caught by the viewmodel during refresh or save operations.
virtual void OnModelChanging(T oldValue, T newValue)
Raises the ModelChanging event
IPropertyInfo GetPropertyInfo(string propertyName)
Get a PropertyInfo object for a property of the Model.
static bool CanGetObject()
Gets a value indicating whether the current user is authorized to retrieve an instance of the busines...
static bool CanEditObject()
Gets a value indicating whether the current user is authorized to edit/save an instance of the busine...
T Model
Gets or sets the Model object.
Action ModelChanged
Event raised when Model has changed
static bool CanCreateObject()
Gets a value indicating whether the current user is authorized to create an instance of the business ...
virtual void OnModelPropertyChanged(string propertyName)
Raises the ModelPropertyChanged event
ViewModel(IDataPortal< T > dataPortal)
Creates an instance of the type
Action Saved
Event raised after Model has been saved
IPropertyInfo GetPropertyInfo(string propertyName, string id)
Get a PropertyInfo object for a property of the Model.
This exception is returned for any errors occurring during the server-side DataPortal invocation.
string BusinessExceptionMessage
Gets the Message property from the BusinessException, falling back to the Message value from the top-...
This is the client-side DataPortal.
Definition: DataPortalT.cs:24
Maintains metadata about a property.
Tracks the business rules for a business object.
static bool HasPermission(AuthorizationActions action, Type objectType)
Checks per-type authorization rules.
Exposes metastate for a property.
Interface defining the members of the data portal type.
Definition: IDataPortal.cs:21
AuthorizationActions
Authorization actions.