using System.Collections.Generic; using System.ComponentModel; using System.Runtime.CompilerServices; using InABox.Core; using Xamarin.Forms; namespace comal.timesheets { public abstract class Shell : BindableObject, INotifyPropertyChanged, IShell where TParent : IModel where TEntity : Entity { #region INotifyPropertyChanged public event PropertyChangedEventHandler PropertyChanged; protected void DoPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } protected bool SetProperty(ref T field, T value, [CallerMemberName] string propertyName = null) { if (EqualityComparer.Default.Equals(field, value)) return false; field = value; DoPropertyChanged(propertyName); return true; } #endregion protected virtual void RowChanged() { } private CoreRow _row = null; public CoreRow Row { get => _row; set { _row = value; RowChanged(); } } public TParent Parent { get; set; } IModel IShell.Parent => this.Parent; #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 _columns = new ShellColumns(); public static ShellColumns Columns { get { return _columns; } } protected virtual T Get([CallerMemberName] string property = null) { var value = Row.Values[Columns.IndexOf(property)]; return value != null ? (T)CoreUtils.ChangeType(value, typeof(T)) : CoreUtils.GetDefault(); } protected virtual void Set(T value, bool notify = true, [CallerMemberName] string property = null) { Row.Values[Columns.IndexOf(property)] = value; if (notify) DoPropertyChanged(property); } #endregion } }