Model.cs 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Diagnostics.CodeAnalysis;
  5. using System.IO;
  6. using System.Linq;
  7. using System.Reflection;
  8. using System.Runtime.CompilerServices;
  9. using InABox.Clients;
  10. using InABox.Core;
  11. using InABox.Mobile;
  12. using Xamarin.Forms;
  13. namespace InABox.Mobile
  14. {
  15. public abstract class Model<TParent, TItem, TEntity> : BindableObject, IModel
  16. where TParent : Model<TParent, TItem, TEntity>, IModel
  17. where TEntity : Entity, IRemotable, IPersistent, new()
  18. where TItem : Shell<TParent, TEntity>, new()
  19. {
  20. public Model(IModelHost host, Func<Filter<TEntity>> filter, bool transient = false)
  21. {
  22. Reset();
  23. new TItem();
  24. Host = host;
  25. Filter = filter;
  26. Type = transient ? ModelType.Transient : ModelType.Normal;
  27. }
  28. public Model(IModelHost host, Func<Filter<TEntity>> filter, [NotNull] String filename)
  29. {
  30. Reset();
  31. new TItem();
  32. Host = host;
  33. Type = ModelType.Persistent;
  34. Filter = filter;
  35. FileName = filename;
  36. }
  37. #region INotifyPropertyChanged
  38. public event PropertyChangedEventHandler PropertyChanged;
  39. protected void DoPropertyChanged(object sender, PropertyChangedEventArgs args)
  40. {
  41. PropertyChanged?.Invoke(sender, args);
  42. }
  43. protected bool SetProperty<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
  44. {
  45. if (EqualityComparer<T>.Default.Equals(field, value)) return false;
  46. field = value;
  47. PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
  48. return true;
  49. }
  50. #endregion
  51. public bool Loaded { get; protected set; }
  52. public abstract void BeforeLoad(MultiQuery query);
  53. public abstract void AfterLoad(MultiQuery query);
  54. public abstract void Load(Action loaded = null);
  55. public abstract IModel Refresh(bool force);
  56. public abstract void Refresh(bool force, Action loaded);
  57. public event ModelChangedEvent Changed;
  58. protected void NotifyChanged() => Changed?.Invoke(this, new ModelChangedEventArgs());
  59. protected abstract void Initialize();
  60. public void Reset()
  61. {
  62. Loaded = false;
  63. Images.Clear();
  64. Initialize();
  65. }
  66. protected Func<Filter<TEntity>> Filter { get; set; }
  67. // // Use "new" to replace this with your actual columns
  68. // public Columns<TEntity> Columns
  69. // {
  70. // get
  71. // {
  72. // var prop = typeof(TItem).GetProperty("Columns",
  73. // BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
  74. // var cols = prop?.GetValue(null) as IShellColumns<TEntity>;
  75. // return cols?.Columns;
  76. // }
  77. // }
  78. protected Columns<TOtherEntity> GetColumns<TOtherItem, TOtherEntity>()
  79. where TOtherItem : Shell<TParent, TOtherEntity>, new()
  80. where TOtherEntity : Entity, IRemotable, IPersistent, new()
  81. {
  82. return new TOtherItem().Columns.Columns;
  83. }
  84. //public IColumns GetColumns() => Columns;
  85. public Dictionary<Guid, byte[]> Images { get; private set; } = new Dictionary<Guid, byte[]>();
  86. public ImageSource GetImage(Guid id)
  87. {
  88. ImageSource result = null;
  89. if (Images.TryGetValue(id, out byte[] data))
  90. result = ImageSource.FromStream(() => new MemoryStream(data));
  91. return result;
  92. }
  93. public bool HasImages() => Images.Any();
  94. public IModelHost Host { get; private set; }
  95. public ModelType Type { get; private set; }
  96. public String FileName { get; private set; }
  97. protected void InitializeTables(MultiQuery query)
  98. {
  99. var defs = query.Definitions();
  100. foreach (var def in defs)
  101. {
  102. var table = InitializeTable(def.Value);
  103. query.Set(def.Key, table);
  104. }
  105. }
  106. protected CoreTable InitializeTable(IQueryDef def)
  107. {
  108. var table = new CoreTable();
  109. if (def.Columns != null)
  110. table.LoadColumns(def.Columns);
  111. else
  112. table.LoadColumns(def.Type);
  113. return table;
  114. }
  115. protected class QueryStorage : ISerializeBinary
  116. {
  117. private Dictionary<String, CoreTable> _data = new Dictionary<string, CoreTable>();
  118. public CoreTable Get([NotNull] String key) => _data[key];
  119. public void Set([NotNull] String key, CoreTable table) => _data[key] = table;
  120. public bool Contains([NotNull] String key) => _data.ContainsKey(key);
  121. public void SerializeBinary(CoreBinaryWriter writer)
  122. {
  123. writer.Write(_data.Count);
  124. foreach (var key in _data.Keys)
  125. {
  126. writer.Write(key);
  127. _data[key].SerializeBinary(writer);
  128. }
  129. }
  130. public void DeserializeBinary(CoreBinaryReader reader)
  131. {
  132. int count = reader.ReadInt32();
  133. for (int i = 0; i < count; i++)
  134. {
  135. String key = reader.ReadString();
  136. CoreTable table = new CoreTable();
  137. table.DeserializeBinary(reader);
  138. _data[key] = table;
  139. }
  140. }
  141. }
  142. protected void LoadFromStorage(MultiQuery query)
  143. {
  144. QueryStorage storage = new QueryStorage();
  145. var file = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), FileName);
  146. if (File.Exists(file))
  147. {
  148. using (var stream = new FileStream(file, FileMode.Open))
  149. storage = Serialization.ReadBinary<QueryStorage>(stream, BinarySerializationSettings.Latest);
  150. var defs = query.Definitions();
  151. foreach (var key in defs.Keys)
  152. {
  153. var table = storage.Contains(key.ToString())
  154. ? storage.Get(key.ToString())
  155. : InitializeTable(defs[key]);
  156. query.Set(key, table);
  157. }
  158. }
  159. else
  160. InitializeTables(query);
  161. }
  162. protected void SaveToStorage(MultiQuery query)
  163. {
  164. QueryStorage storage = new QueryStorage();
  165. var results = query.Results();
  166. foreach (var key in results.Keys)
  167. storage.Set(key.ToString(),results[key]);
  168. var data = storage.WriteBinary(BinarySerializationSettings.Latest);
  169. try
  170. {
  171. var file = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), FileName);
  172. File.WriteAllBytes(file,data);
  173. }
  174. catch (Exception e)
  175. {
  176. MobileLogging.Log(e);
  177. }
  178. }
  179. }
  180. }