|
|
@@ -4,202 +4,200 @@ using DynamicData.Binding;
|
|
|
using InABox.Clients;
|
|
|
using InABox.Core;
|
|
|
|
|
|
-namespace InABox.Avalonia
|
|
|
+namespace InABox.Avalonia;
|
|
|
+
|
|
|
+public abstract class Shell<TParent,TEntity> : INotifyPropertyChanged, IShell, IShell<TEntity>
|
|
|
+ where TParent : ICoreRepository
|
|
|
+ where TEntity : Entity, IPersistent, IRemotable, new()
|
|
|
{
|
|
|
- public abstract class Shell<TParent,TEntity> : INotifyPropertyChanged, IShell, IShell<TEntity>
|
|
|
- where TParent : ICoreRepository
|
|
|
- where TEntity : Entity, IPersistent, IRemotable, new()
|
|
|
+ private object? _tag;
|
|
|
+ public object? Tag
|
|
|
{
|
|
|
- private object? _tag;
|
|
|
- public object? Tag
|
|
|
- {
|
|
|
- get => _tag;
|
|
|
- set => SetProperty(ref _tag, value);
|
|
|
- }
|
|
|
+ get => _tag;
|
|
|
+ set => SetProperty(ref _tag, value);
|
|
|
+ }
|
|
|
|
|
|
- private bool _isSelected;
|
|
|
- public bool IsSelected
|
|
|
+ private bool _isSelected;
|
|
|
+ public bool IsSelected
|
|
|
+ {
|
|
|
+ get => _isSelected;
|
|
|
+ set
|
|
|
{
|
|
|
- get => _isSelected;
|
|
|
- set
|
|
|
+ if(_isSelected != value)
|
|
|
{
|
|
|
- if(_isSelected != value)
|
|
|
- {
|
|
|
- _isSelected = value;
|
|
|
- DoPropertyChanged(nameof(IsSelected));
|
|
|
- }
|
|
|
+ _isSelected = value;
|
|
|
+ DoPropertyChanged(nameof(IsSelected));
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- #region INotifyPropertyChanged
|
|
|
-
|
|
|
- public event PropertyChangedEventHandler? PropertyChanged;
|
|
|
-
|
|
|
- protected void DoPropertyChanged(string propertyName)
|
|
|
- {
|
|
|
- PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
|
- }
|
|
|
-
|
|
|
- protected bool SetProperty<T>(ref T field, T value, [CallerMemberName] string propertyName = "")
|
|
|
- {
|
|
|
- if (EqualityComparer<T>.Default.Equals(field, value)) return false;
|
|
|
- field = value;
|
|
|
- DoPropertyChanged(propertyName);
|
|
|
- return true;
|
|
|
- }
|
|
|
+ }
|
|
|
+
|
|
|
+ #region INotifyPropertyChanged
|
|
|
+
|
|
|
+ public event PropertyChangedEventHandler? PropertyChanged;
|
|
|
+
|
|
|
+ protected void DoPropertyChanged(string propertyName)
|
|
|
+ {
|
|
|
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
|
+ }
|
|
|
+
|
|
|
+ protected bool SetProperty<T>(ref T field, T value, [CallerMemberName] string propertyName = "")
|
|
|
+ {
|
|
|
+ if (EqualityComparer<T>.Default.Equals(field, value)) return false;
|
|
|
+ field = value;
|
|
|
+ DoPropertyChanged(propertyName);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
|
|
|
-
|
|
|
- #endregion
|
|
|
+
|
|
|
+ #endregion
|
|
|
|
|
|
- private TEntity? _entity;
|
|
|
-
|
|
|
- private TEntity CheckEntity()
|
|
|
- {
|
|
|
- _entity ??= Row.ToObject<TEntity>();
|
|
|
- _entity.PropertyCascaded -= _entity_PropertyChanged;
|
|
|
- _entity.PropertyCascaded += _entity_PropertyChanged;
|
|
|
- return _entity;
|
|
|
- }
|
|
|
+ private TEntity? _entity;
|
|
|
+
|
|
|
+ private TEntity CheckEntity()
|
|
|
+ {
|
|
|
+ _entity ??= Row.ToObject<TEntity>();
|
|
|
+ _entity.PropertyCascaded -= _entity_PropertyChanged;
|
|
|
+ _entity.PropertyCascaded += _entity_PropertyChanged;
|
|
|
+ return _entity;
|
|
|
+ }
|
|
|
|
|
|
- private void _entity_PropertyChanged(object? sender, PropertyChangedEventArgs e)
|
|
|
+ private void _entity_PropertyChanged(object? sender, PropertyChangedEventArgs e)
|
|
|
+ {
|
|
|
+ if(e.PropertyName is not null && Columns.FindShellProperty(e.PropertyName) is string property)
|
|
|
{
|
|
|
- if(e.PropertyName is not null && Columns.FindShellProperty(e.PropertyName) is string property)
|
|
|
- {
|
|
|
- DoPropertyChanged(property);
|
|
|
- }
|
|
|
+ DoPropertyChanged(property);
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- public TEntity Entity => CheckEntity();
|
|
|
-
|
|
|
- protected virtual void RowChanged()
|
|
|
- {
|
|
|
- }
|
|
|
+ public TEntity Entity => CheckEntity();
|
|
|
+
|
|
|
+ protected virtual void RowChanged()
|
|
|
+ {
|
|
|
+ }
|
|
|
|
|
|
- public bool IsChanged() => _entity?.IsChanged() ?? false;
|
|
|
+ public bool IsChanged() => _entity?.IsChanged() ?? false;
|
|
|
|
|
|
- public void SyncRow()
|
|
|
- {
|
|
|
- Row.Table.FillRow(Row, Entity);
|
|
|
- }
|
|
|
-
|
|
|
- public virtual void Save(string auditmessage)
|
|
|
+ public void SyncRow()
|
|
|
+ {
|
|
|
+ Row.Table.FillRow(Row, Entity);
|
|
|
+ }
|
|
|
+
|
|
|
+ public virtual void Save(string auditmessage)
|
|
|
+ {
|
|
|
+ if (_entity != null)
|
|
|
{
|
|
|
- if (_entity != null)
|
|
|
- {
|
|
|
- new Client<TEntity>().Save(_entity, auditmessage);
|
|
|
- _entity.CommitChanges();
|
|
|
- SyncRow();
|
|
|
- }
|
|
|
+ new Client<TEntity>().Save(_entity, auditmessage);
|
|
|
+ _entity.CommitChanges();
|
|
|
+ SyncRow();
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- public Task SaveAsync(string auditMessage)
|
|
|
- {
|
|
|
- return Task.Run(() => Save(auditMessage));
|
|
|
- }
|
|
|
+ public Task SaveAsync(string auditMessage)
|
|
|
+ {
|
|
|
+ return Task.Run(() => Save(auditMessage));
|
|
|
+ }
|
|
|
|
|
|
- public void Cancel()
|
|
|
- {
|
|
|
- _entity?.CancelChanges();
|
|
|
- }
|
|
|
-
|
|
|
- private CoreRow _row = null!;
|
|
|
- public CoreRow Row
|
|
|
+ public void Cancel()
|
|
|
+ {
|
|
|
+ _entity?.CancelChanges();
|
|
|
+ }
|
|
|
+
|
|
|
+ private CoreRow _row = null!;
|
|
|
+ public CoreRow Row
|
|
|
+ {
|
|
|
+ get => _row;
|
|
|
+ set
|
|
|
{
|
|
|
- get => _row;
|
|
|
- set
|
|
|
- {
|
|
|
- _row = value;
|
|
|
- RowChanged();
|
|
|
- }
|
|
|
+ _row = value;
|
|
|
+ RowChanged();
|
|
|
}
|
|
|
-
|
|
|
- public TParent Parent { get; set; }
|
|
|
+ }
|
|
|
+
|
|
|
+ public TParent Parent { get; set; }
|
|
|
|
|
|
- ICoreRepository IShell.Parent => this.Parent;
|
|
|
+ ICoreRepository IShell.Parent => this.Parent;
|
|
|
|
|
|
- public Guid ID => Get<Guid>();
|
|
|
+ public Guid ID => Get<Guid>();
|
|
|
|
|
|
- public virtual string[] TextSearchValues() => [];
|
|
|
-
|
|
|
- public bool Match(string? text)
|
|
|
+ public virtual string[] TextSearchValues() => [];
|
|
|
+
|
|
|
+ public bool Match(string? text)
|
|
|
+ {
|
|
|
+ if (string.IsNullOrWhiteSpace(text))
|
|
|
+ return true;
|
|
|
+ foreach (var value in TextSearchValues())
|
|
|
{
|
|
|
- if (string.IsNullOrWhiteSpace(text))
|
|
|
+ if (value.Contains(text, StringComparison.InvariantCultureIgnoreCase))
|
|
|
return true;
|
|
|
- foreach (var value in TextSearchValues())
|
|
|
- {
|
|
|
- if (value.Contains(text, StringComparison.InvariantCultureIgnoreCase))
|
|
|
- return true;
|
|
|
- }
|
|
|
- return false;
|
|
|
}
|
|
|
-
|
|
|
- #region Row Get/Set Caching
|
|
|
-
|
|
|
- // We do this for three reasons:
|
|
|
- // 1. Rather than define properties in once class and columns in another,
|
|
|
- // we can define and link properties and columns in the one class,
|
|
|
- // using a _static_ constructor, which reduces complexity
|
|
|
- // 2. By caching based on the property name, we eliminate the need to convert
|
|
|
- // expressions to strings (expensive), while still retaining type-safety
|
|
|
- // 3. Using the Get/Set helper functions reduces code complexity when defining
|
|
|
- // shell properties, and distinguishes between data and calculated properties
|
|
|
-
|
|
|
- private static ShellColumns<TParent, TEntity>? _columns;
|
|
|
-
|
|
|
- public ShellColumns<TParent, TEntity> Columns
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ #region Row Get/Set Caching
|
|
|
+
|
|
|
+ // We do this for three reasons:
|
|
|
+ // 1. Rather than define properties in once class and columns in another,
|
|
|
+ // we can define and link properties and columns in the one class,
|
|
|
+ // using a _static_ constructor, which reduces complexity
|
|
|
+ // 2. By caching based on the property name, we eliminate the need to convert
|
|
|
+ // expressions to strings (expensive), while still retaining type-safety
|
|
|
+ // 3. Using the Get/Set helper functions reduces code complexity when defining
|
|
|
+ // shell properties, and distinguishes between data and calculated properties
|
|
|
+
|
|
|
+ private static ShellColumns<TParent, TEntity>? _columns;
|
|
|
+
|
|
|
+ public ShellColumns<TParent, TEntity> Columns
|
|
|
+ {
|
|
|
+ get
|
|
|
{
|
|
|
- get
|
|
|
+ if (_columns == null)
|
|
|
{
|
|
|
- if (_columns == null)
|
|
|
- {
|
|
|
- _columns = new ShellColumns<TParent, TEntity>();
|
|
|
- _columns.Map(nameof(ID), x => x.ID);
|
|
|
- ConfigureColumns(_columns);
|
|
|
- }
|
|
|
- return _columns;
|
|
|
+ _columns = new ShellColumns<TParent, TEntity>();
|
|
|
+ _columns.Map(nameof(ID), x => x.ID);
|
|
|
+ ConfigureColumns(_columns);
|
|
|
}
|
|
|
+ return _columns;
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- protected abstract void ConfigureColumns(ShellColumns<TParent, TEntity> columns);
|
|
|
+ protected abstract void ConfigureColumns(ShellColumns<TParent, TEntity> columns);
|
|
|
|
|
|
- protected virtual T Get<T>([CallerMemberName] string property = null)
|
|
|
+ protected virtual T Get<T>([CallerMemberName] string property = null)
|
|
|
+ {
|
|
|
+ if (_entity != null)
|
|
|
{
|
|
|
- if (_entity != null)
|
|
|
- {
|
|
|
- return (T)CoreUtils.GetPropertyValue(
|
|
|
- _entity,
|
|
|
- Columns[property]
|
|
|
- );
|
|
|
- }
|
|
|
-
|
|
|
- if (_row != null)
|
|
|
- {
|
|
|
- var col = _columns?.IndexOf(property);
|
|
|
- if (col != null)
|
|
|
- return Row.Get<T>(col.Value); //() Row.Values[];
|
|
|
- }
|
|
|
-
|
|
|
- return CoreUtils.GetDefault<T>();
|
|
|
-
|
|
|
- //return value != null ? (T)CoreUtils.ChangeType(value, typeof(T)) : CoreUtils.GetDefault<T>();
|
|
|
+ return (T)CoreUtils.GetPropertyValue(
|
|
|
+ _entity,
|
|
|
+ Columns[property]
|
|
|
+ );
|
|
|
}
|
|
|
-
|
|
|
- protected virtual void Set<T>(T value, bool donotify = true, [CallerMemberName] string property = null, params string[] notify)
|
|
|
+
|
|
|
+ if (_row != null)
|
|
|
{
|
|
|
- CheckEntity();
|
|
|
- CoreUtils.SetPropertyValue(_entity, Columns[property], value);
|
|
|
- //Row.Values[Columns.IndexOf(property)] = value;
|
|
|
- // if (donotify)
|
|
|
- // {
|
|
|
- // DoPropertyChanged(property);
|
|
|
- // foreach (var _property in notify)
|
|
|
- // DoPropertyChanged(_property);
|
|
|
- // }
|
|
|
+ var col = _columns?.IndexOf(property);
|
|
|
+ if (col != null)
|
|
|
+ return Row.Get<T>(col.Value); //() Row.Values[];
|
|
|
}
|
|
|
-
|
|
|
|
|
|
- #endregion
|
|
|
-
|
|
|
+ return CoreUtils.GetDefault<T>();
|
|
|
+
|
|
|
+ //return value != null ? (T)CoreUtils.ChangeType(value, typeof(T)) : CoreUtils.GetDefault<T>();
|
|
|
+ }
|
|
|
+
|
|
|
+ protected virtual void Set<T>(T value, bool donotify = true, [CallerMemberName] string property = null, params string[] notify)
|
|
|
+ {
|
|
|
+ CheckEntity();
|
|
|
+ CoreUtils.SetPropertyValue(_entity, Columns[property], value);
|
|
|
+ //Row.Values[Columns.IndexOf(property)] = value;
|
|
|
+ // if (donotify)
|
|
|
+ // {
|
|
|
+ // DoPropertyChanged(property);
|
|
|
+ // foreach (var _property in notify)
|
|
|
+ // DoPropertyChanged(_property);
|
|
|
+ // }
|
|
|
}
|
|
|
+
|
|
|
|
|
|
+ #endregion
|
|
|
+
|
|
|
}
|