aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio
diff options
context:
space:
mode:
authorRoy Ben-Shabat <Roy@Twine-s.com>2018-08-01 10:29:09 +0300
committerRoy Ben-Shabat <Roy@Twine-s.com>2018-08-01 10:29:09 +0300
commitd5c6067365e12674e95acaef4c4af45eaead8c3e (patch)
tree0345d7e407a3e714061dc9bc26152c9efe977bd9 /Software/Visual_Studio
parent91c672c0b0b01bc68a6adfa2aada337c6488a614 (diff)
downloadTango-d5c6067365e12674e95acaef4c4af45eaead8c3e.tar.gz
Tango-d5c6067365e12674e95acaef4c4af45eaead8c3e.zip
Implemented notification for observables entities modification..
Diffstat (limited to 'Software/Visual_Studio')
-rw-r--r--Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/ViewModels/MainViewVM.cs4
-rw-r--r--Software/Visual_Studio/Tango.BL/IObservableEntity.cs9
-rw-r--r--Software/Visual_Studio/Tango.BL/ObservableEntity.cs226
-rw-r--r--Software/Visual_Studio/Tango.BL/ObservableModifiedEventArgs.cs43
-rw-r--r--Software/Visual_Studio/Tango.BL/ObservablesContextExtension.cs38
-rw-r--r--Software/Visual_Studio/Tango.BL/Tango.BL.csproj3
-rw-r--r--Software/Visual_Studio/Tango.Core/ExtendedObject.cs47
7 files changed, 258 insertions, 112 deletions
diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/ViewModels/MainViewVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/ViewModels/MainViewVM.cs
index a58757633..9ac78ccec 100644
--- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/ViewModels/MainViewVM.cs
+++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Developer/ViewModels/MainViewVM.cs
@@ -180,8 +180,8 @@ namespace Tango.MachineStudio.Developer.ViewModels
if (_selectedMachine != null)
{
- _selectedMachine.Saved -= SelectedMachine_Saved;
- _selectedMachine.Saved += SelectedMachine_Saved;
+ _selectedMachine.Modified -= SelectedMachine_Saved;
+ _selectedMachine.Modified += SelectedMachine_Saved;
}
}
}
diff --git a/Software/Visual_Studio/Tango.BL/IObservableEntity.cs b/Software/Visual_Studio/Tango.BL/IObservableEntity.cs
index d83f3a6b2..ad112c4a1 100644
--- a/Software/Visual_Studio/Tango.BL/IObservableEntity.cs
+++ b/Software/Visual_Studio/Tango.BL/IObservableEntity.cs
@@ -17,9 +17,9 @@ namespace Tango.BL
public interface IObservableEntity : INotifyDataErrorInfo, IParameterized
{
/// <summary>
- /// Occurs after this observable has been saved.
+ /// Occurs after this observable has been modified and saved by this entity context or another.
/// </summary>
- event EventHandler Saved;
+ event EventHandler<ObservableModifiedEventArgs> Modified;
/// <summary>
/// Gets or sets the entity identifier.
@@ -92,5 +92,10 @@ namespace Tango.BL
/// <param name="context">The context.</param>
/// <returns></returns>
DbSet<T> GetDbSet<T>(ObservablesContext context) where T : class, IObservableEntity;
+
+ /// <summary>
+ /// Raises the <see cref="Modified"/> event.
+ /// </summary>
+ void RaiseModified(ObservablesContext context, IObservableEntity source, IObservableEntity target);
}
}
diff --git a/Software/Visual_Studio/Tango.BL/ObservableEntity.cs b/Software/Visual_Studio/Tango.BL/ObservableEntity.cs
index 4f002c073..fc037f16a 100644
--- a/Software/Visual_Studio/Tango.BL/ObservableEntity.cs
+++ b/Software/Visual_Studio/Tango.BL/ObservableEntity.cs
@@ -26,6 +26,19 @@ using System.ComponentModel;
namespace Tango.BL
{
+ internal class ObservableEntitiesContainer
+ {
+ static ObservableEntitiesContainer()
+ {
+ RegisteredEntities = new List<IObservableEntity>();
+ }
+
+ /// <summary>
+ /// Gets the list of all registered entities ever created.
+ /// </summary>
+ internal static List<IObservableEntity> RegisteredEntities { get; private set; }
+ }
+
/// <summary>
/// Represents a generic observable entity base class.
/// </summary>
@@ -35,13 +48,16 @@ namespace Tango.BL
[Serializable]
public abstract class ObservableEntity<T> : ExtendedObject, IObservableEntity where T : class, IObservableEntity
{
- private Regex regExDAL;
- private List<KeyValuePair<String, String>> _currentErrors = new List<KeyValuePair<string, string>>(); //Holds the current validation errors.
+ #region Events
/// <summary>
- /// Occurs after this observable has been saved.
+ /// Occurs after this observable has been modified and saved by this entity context or another.
/// </summary>
- public event EventHandler Saved;
+ public event EventHandler<ObservableModifiedEventArgs> Modified;
+
+ #endregion
+
+ #region Properties
private Int32 _id;
/// <summary>
@@ -117,19 +133,25 @@ namespace Tango.BL
get { return GetType(); }
}
+ #endregion
+
+ #region Constructors
+
/// <summary>
/// Initializes a new instance of the <see cref="ObservableEntity{T}"/> class.
/// </summary>
public ObservableEntity()
{
+ ObservableEntitiesContainer.RegisteredEntities.Add(this);
+
Guid = System.Guid.NewGuid().ToString();
LastUpdated = DateTime.UtcNow;
- regExDAL = new Regex(@"
- (?<=[A-Z])(?=[A-Z][a-z]) |
- (?<=[^A-Z])(?=[A-Z]) |
- (?<=[A-Za-z])(?=[^A-Za-z])", RegexOptions.IgnorePatternWhitespace);
}
+ #endregion
+
+ #region Public Methods
+
/// <summary>
/// Saves the changes on this entity to database.
/// </summary>
@@ -155,7 +177,6 @@ namespace Tango.BL
{
context.SaveChanges();
}
- OnSaved();
}
/// <summary>
@@ -246,6 +267,11 @@ Maybe you have deleted an entity that was no yet inserted into database?", LogCa
});
}
+ /// <summary>
+ /// Gets the database set.
+ /// </summary>
+ /// <param name="context">The context.</param>
+ /// <returns></returns>
public DbSet<T> GetDbSet(ObservablesContext context)
{
String tabelName = this.GetType().Name.PluralizeMVC();
@@ -269,12 +295,77 @@ Maybe you have deleted an entity that was no yet inserted into database?", LogCa
return null;
}
- protected virtual void OnSaved()
+ /// <summary>
+ /// Gets the database set.
+ /// </summary>
+ /// <typeparam name="T1">The type of the 1.</typeparam>
+ /// <param name="context">The context.</param>
+ /// <returns></returns>
+ public DbSet<T1> GetDbSet<T1>(ObservablesContext context) where T1 : class, IObservableEntity
{
- Saved?.Invoke(this, new EventArgs());
+ return GetDbSet(context) as DbSet<T1>;
}
- public static DbContext GetDbContextFromEntity(object entity)
+ /// <summary>
+ /// Clones this entity.
+ /// </summary>
+ /// <returns></returns>
+ public virtual T Clone()
+ {
+ var cloned = Activator.CreateInstance<T>();
+
+ foreach (var prop in typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(x => x.SetMethod != null))
+ {
+ if (!prop.PropertyType.IsGenericType)
+ {
+ prop.SetValue(cloned, prop.GetValue(this));
+ }
+ }
+
+ cloned.ID = 0;
+ cloned.Guid = System.Guid.NewGuid().ToString();
+ cloned.LastUpdated = DateTime.UtcNow;
+ return cloned;
+ }
+
+ /// <summary>
+ /// Compares another entity using a a JSON string comparison.
+ /// </summary>
+ /// <param name="entity">The entity.</param>
+ /// <returns></returns>
+ public bool CompareUsingJson(T entity)
+ {
+ String me = JsonConvert.SerializeObject(this);
+ String other = JsonConvert.SerializeObject(entity);
+ return me == other;
+ }
+
+ /// <summary>
+ /// Deletes this entity using an SQL statement which will cause the database delete cascade effect.
+ /// </summary>
+ /// <param name="context"></param>
+ /// <returns></returns>
+ public Task DeleteCascadeAsync(ObservablesContext context)
+ {
+ return context.Database.ExecuteSqlCommandAsync(String.Format("DELETE FROM {0} WHERE GUID='{1}'", this.GetType().GetCustomAttribute<TableAttribute>().Name, Guid));
+ }
+
+ /// <summary>
+ /// Raises the <see cref="Modified" /> event.
+ /// </summary>
+ /// <param name="context"></param>
+ /// <param name="source"></param>
+ /// <param name="target"></param>
+ public void RaiseModified(ObservablesContext context, IObservableEntity source, IObservableEntity target)
+ {
+ Modified?.Invoke(this, new ObservableModifiedEventArgs(context, source, target));
+ }
+
+ #endregion
+
+ #region Private Methods
+
+ private static DbContext GetDbContextFromEntity(object entity)
{
var object_context = GetObjectContextFromEntity(entity);
@@ -298,26 +389,52 @@ Maybe you have deleted an entity that was no yet inserted into database?", LogCa
return context;
}
- public virtual T Clone()
+ #endregion
+
+ #region Validation
+
+ //Holds the current validation errors.
+ private List<KeyValuePair<String, String>> _currentErrors = new List<KeyValuePair<string, string>>();
+
+ /// <summary>
+ /// Occurs when the validation errors have changed for a property or for the entire entity.
+ /// </summary>
+ public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
+
+ private ObservableCollection<String> _validationErrors;
+ /// <summary>
+ /// Gets or sets the validation errors.
+ /// </summary>
+ [NotMapped]
+ [ParameterIgnore]
+ [XmlIgnore]
+ public ObservableCollection<String> ValidationErrors
{
- return (this as T).CloneEntity() as T;
+ get { return _validationErrors; }
+ protected set { _validationErrors = value; RaisePropertyChangedAuto(); }
}
- public bool CompareUsingJson(T entity)
+ private bool _validateOnPropertyChanged;
+ [NotMapped]
+ [ParameterIgnore]
+ [XmlIgnore]
+ public bool ValidateOnPropertyChanged
{
- String me = JsonConvert.SerializeObject(this);
- String other = JsonConvert.SerializeObject(entity);
- return me == other;
+ get { return _validateOnPropertyChanged; }
+ set { _validateOnPropertyChanged = value; RaisePropertyChangedAuto(); }
}
+ private bool _hasErrors;
/// <summary>
- /// Deletes this entity using an SQL statement which will cause the database delete cascade effect.
+ /// Gets a value that indicates whether the entity has validation errors.
/// </summary>
- /// <param name="context"></param>
- /// <returns></returns>
- public Task DeleteCascadeAsync(ObservablesContext context)
+ [NotMapped]
+ [ParameterIgnore]
+ [XmlIgnore]
+ public bool HasErrors
{
- return context.Database.ExecuteSqlCommandAsync(String.Format("DELETE FROM {0} WHERE GUID='{1}'", this.GetType().GetCustomAttribute<TableAttribute>().Name, Guid));
+ get { return _hasErrors; }
+ set { _hasErrors = value; RaisePropertyChangedAuto(); }
}
/// <summary>
@@ -357,37 +474,36 @@ Maybe you have deleted an entity that was no yet inserted into database?", LogCa
return !HasErrors;
}
- public DbSet<T1> GetDbSet<T1>(ObservablesContext context) where T1 : class, IObservableEntity
- {
- return GetDbSet(context) as DbSet<T1>;
- }
-
+ /// <summary>
+ /// Gets the validation errors for a specified property or for the entire entity.
+ /// </summary>
+ /// <param name="propertyName">The name of the property to retrieve validation errors for; or null or <see cref="F:System.String.Empty" />, to retrieve entity-level errors.</param>
+ /// <returns>
+ /// The validation errors for the property or entity.
+ /// </returns>
public IEnumerable GetErrors(string propertyName)
{
return _currentErrors.Where(x => x.Key == propertyName).Select(x => x.Value).ToList();
}
+ /// <summary>
+ /// Called when entity is validating.
+ /// </summary>
protected virtual void OnValidating(ObservablesContext context)
{
}
+ /// <summary>
+ /// Inserts the error.
+ /// </summary>
+ /// <param name="propName">Name of the property.</param>
+ /// <param name="error">The error.</param>
protected void InsertError(String propName, String error)
{
_currentErrors.Add(new KeyValuePair<string, string>(propName, error));
}
- private bool _validateOnPropertyChanged;
- [NotMapped]
- [ParameterIgnore]
- [XmlIgnore]
- public bool ValidateOnPropertyChanged
- {
- get { return _validateOnPropertyChanged; }
- set { _validateOnPropertyChanged = value; RaisePropertyChangedAuto(); }
- }
-
-
/// <summary>
/// Invoked the <see cref="ErrorsChanged"/> event.
/// </summary>
@@ -397,34 +513,14 @@ Maybe you have deleted an entity that was no yet inserted into database?", LogCa
ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propName));
}
- private bool _hasErrors;
- /// <summary>
- /// Gets a value that indicates whether the entity has validation errors.
- /// </summary>
- [NotMapped]
- [ParameterIgnore]
- [XmlIgnore]
- public bool HasErrors
- {
- get { return _hasErrors; }
- set { _hasErrors = value; RaisePropertyChangedAuto(); }
- }
+ #endregion
+
+ #region INotify Property Changed
- private ObservableCollection<String> _validationErrors;
/// <summary>
- /// Gets or sets the validation errors.
+ /// Raises the property changed event.
/// </summary>
- [NotMapped]
- [ParameterIgnore]
- [XmlIgnore]
- public ObservableCollection<String> ValidationErrors
- {
- get { return _validationErrors; }
- protected set { _validationErrors = value; RaisePropertyChangedAuto(); }
- }
-
- public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
-
+ /// <param name="propName">Name of the property.</param>
protected override void RaisePropertyChanged(string propName)
{
base.RaisePropertyChanged(propName);
@@ -435,6 +531,8 @@ Maybe you have deleted an entity that was no yet inserted into database?", LogCa
}
}
+ #endregion
+
#region Operator Overloading
//public static bool operator ==(ObservableEntity<T> observable1, ObservableEntity<T> observable2)
diff --git a/Software/Visual_Studio/Tango.BL/ObservableModifiedEventArgs.cs b/Software/Visual_Studio/Tango.BL/ObservableModifiedEventArgs.cs
new file mode 100644
index 000000000..2b49154b3
--- /dev/null
+++ b/Software/Visual_Studio/Tango.BL/ObservableModifiedEventArgs.cs
@@ -0,0 +1,43 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tango.BL
+{
+ /// <summary>
+ /// Represents an observable modified event arguments.
+ /// </summary>
+ /// <seealso cref="System.EventArgs" />
+ public class ObservableModifiedEventArgs : EventArgs
+ {
+ /// <summary>
+ /// Gets or sets the modified entity context.
+ /// </summary>
+ public ObservablesContext Context { get; set; }
+
+ /// <summary>
+ /// Gets or sets the modified entity.
+ /// </summary>
+ public IObservableEntity ModifiedEntity { get; set; }
+
+ /// <summary>
+ /// Gets or sets the notified entity.
+ /// </summary>
+ public IObservableEntity NotifiedEntity { get; set; }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ObservableModifiedEventArgs"/> class.
+ /// </summary>
+ /// <param name="context">The context.</param>
+ /// <param name="source">The source.</param>
+ /// <param name="target">The target.</param>
+ public ObservableModifiedEventArgs(ObservablesContext context, IObservableEntity source, IObservableEntity target)
+ {
+ Context = context;
+ ModifiedEntity = source;
+ NotifiedEntity = target;
+ }
+ }
+}
diff --git a/Software/Visual_Studio/Tango.BL/ObservablesContextExtension.cs b/Software/Visual_Studio/Tango.BL/ObservablesContextExtension.cs
index 1473845c5..7c3ade821 100644
--- a/Software/Visual_Studio/Tango.BL/ObservablesContextExtension.cs
+++ b/Software/Visual_Studio/Tango.BL/ObservablesContextExtension.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Data.Entity;
+using System.Data.Entity.Infrastructure;
using System.Data.SQLite;
using System.IO;
using System.Linq;
@@ -56,7 +57,8 @@ namespace Tango.BL
/// <returns></returns>
public static ObservablesContext CreateDefault()
{
- return CreateDefault(SettingsManager.Default.GetOrCreate<CoreSettings>().DataBaseSource);
+ var context = CreateDefault(SettingsManager.Default.GetOrCreate<CoreSettings>().DataBaseSource);
+ return context;
}
/// <summary>
@@ -81,5 +83,39 @@ namespace Tango.BL
return new ObservablesContext(source);
}
}
+
+ /// <summary>
+ /// Saves all changes made in this context to the underlying database.
+ /// </summary>
+ /// <returns>
+ /// The number of objects written to the underlying database.
+ /// </returns>
+ public override int SaveChanges()
+ {
+ return base.SaveChanges();
+ }
+
+ /// <summary>
+ /// Extension point allowing the user to override the default behavior of validating only
+ /// added and modified entities.
+ /// </summary>
+ /// <param name="entityEntry">DbEntityEntry instance that is supposed to be validated.</param>
+ /// <returns>
+ /// true to proceed with validation; false otherwise.
+ /// </returns>
+ protected override bool ShouldValidateEntity(DbEntityEntry entityEntry)
+ {
+ if (entityEntry.State == EntityState.Modified && entityEntry.Entity is IObservableEntity)
+ {
+ IObservableEntity modified = entityEntry.Entity as IObservableEntity;
+
+ Parallel.ForEach(ObservableEntitiesContainer.RegisteredEntities.Where(x => x.Guid == modified.Guid), (toNotify) =>
+ {
+ toNotify.RaiseModified(this, modified, toNotify);
+ });
+ }
+
+ return base.ShouldValidateEntity(entityEntry);
+ }
}
}
diff --git a/Software/Visual_Studio/Tango.BL/Tango.BL.csproj b/Software/Visual_Studio/Tango.BL/Tango.BL.csproj
index 1553ab1f5..58767ea88 100644
--- a/Software/Visual_Studio/Tango.BL/Tango.BL.csproj
+++ b/Software/Visual_Studio/Tango.BL/Tango.BL.csproj
@@ -234,6 +234,7 @@
<Compile Include="ExtensionMethods\ProcessParametersTablesGroupExtensions.cs" />
<Compile Include="IObservableEntity.cs" />
<Compile Include="ObservableEntity.cs" />
+ <Compile Include="ObservableModifiedEventArgs.cs" />
<Compile Include="ObservablesContext.cs" />
<Compile Include="ObservablesContextExtension.cs" />
<Compile Include="ObservablesEntitiesAdapter.cs" />
@@ -315,7 +316,7 @@
</Target>
<ProjectExtensions>
<VisualStudio>
- <UserProperties BuildVersion_StartDate="2000/1/1" BuildVersion_UseGlobalSettings="False" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" />
+ <UserProperties BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_UseGlobalSettings="False" BuildVersion_StartDate="2000/1/1" />
</VisualStudio>
</ProjectExtensions>
</Project> \ No newline at end of file
diff --git a/Software/Visual_Studio/Tango.Core/ExtendedObject.cs b/Software/Visual_Studio/Tango.Core/ExtendedObject.cs
index 03ac703ae..44663b503 100644
--- a/Software/Visual_Studio/Tango.Core/ExtendedObject.cs
+++ b/Software/Visual_Studio/Tango.Core/ExtendedObject.cs
@@ -23,16 +23,6 @@ namespace Tango.Core
public class ExtendedObject : INotifyPropertyChanged
{
/// <summary>
- /// Gets or sets a value indicating whether to globally disable property changed on extended objects.
- /// </summary>
- public static bool DisablePropertyChanged { get; set; }
-
- /// <summary>
- /// Gets or sets a value indicating whether to globally disable UI invokations on extended objects.
- /// </summary>
- public static bool DisableUIInvokation { get; set; }
-
- /// <summary>
/// Occurs when after InvalidateRelayCommands is called.
/// </summary>
[field: NonSerialized]
@@ -70,10 +60,7 @@ namespace Tango.Core
/// <param name="propName">Name of the property.</param>
protected virtual void RaisePropertyChanged(String propName)
{
- if (!DisablePropertyChanged)
- {
- PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
- }
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
}
/// <summary>
@@ -82,10 +69,7 @@ namespace Tango.Core
/// <param name="propName">Name of the property.</param>
protected virtual void RaisePropertyChangedAuto([CallerMemberName] string caller = null)
{
- if (!DisablePropertyChanged)
- {
- PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(caller));
- }
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(caller));
}
/// <summary>
@@ -125,14 +109,7 @@ namespace Tango.Core
/// <param name="action">The action.</param>
protected virtual void InvokeUI(Action action)
{
- if (!DisableUIInvokation)
- {
- Application.Current.Dispatcher.BeginInvoke(action);
- }
- else
- {
- action();
- }
+ Application.Current.Dispatcher.BeginInvoke(action);
}
/// <summary>
@@ -141,14 +118,7 @@ namespace Tango.Core
/// <param name="action">The action.</param>
protected virtual void InvokeUIOnIdle(Action action)
{
- if (!DisableUIInvokation)
- {
- Application.Current.Dispatcher.BeginInvoke(action, DispatcherPriority.ContextIdle);
- }
- else
- {
- action();
- }
+ Application.Current.Dispatcher.BeginInvoke(action, DispatcherPriority.ContextIdle);
}
/// <summary>
@@ -157,14 +127,7 @@ namespace Tango.Core
/// <param name="action">The action.</param>
protected virtual void InvokeUINow(Action action)
{
- if (!DisableUIInvokation)
- {
- Application.Current.Dispatcher.Invoke(action);
- }
- else
- {
- action();
- }
+ Application.Current.Dispatcher.Invoke(action);
}
}
}