Model.cs 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  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 comal.timesheets
  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 void Refresh(bool force, Action loaded = null);
  56. protected abstract void Initialize();
  57. public void Reset()
  58. {
  59. Loaded = false;
  60. Images.Clear();
  61. Initialize();
  62. }
  63. protected Func<Filter<TEntity>> Filter { get; set; }
  64. // Use "new" to replace this with your actual columns
  65. public Columns<TEntity> Columns
  66. {
  67. get
  68. {
  69. var prop = typeof(TItem).GetProperty("Columns",
  70. BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
  71. var cols = prop?.GetValue(null) as IShellColumns<TEntity>;
  72. return cols?.Columns;
  73. }
  74. }
  75. public IColumns GetColumns() => Columns;
  76. public Dictionary<Guid, byte[]> Images { get; private set; } = new Dictionary<Guid, byte[]>();
  77. public ImageSource GetImage(Guid id)
  78. {
  79. ImageSource result = null;
  80. if (Images.TryGetValue(id, out byte[] data))
  81. result = ImageSource.FromStream(() => new MemoryStream(data));
  82. return result;
  83. }
  84. public bool HasImages() => Images.Any();
  85. public IModelHost Host { get; private set; }
  86. public ModelType Type { get; private set; }
  87. public String FileName { get; private set; }
  88. protected void InitializeTables(MultiQuery query)
  89. {
  90. var defs = query.Definitions();
  91. foreach (var def in defs)
  92. {
  93. var table = InitializeTable(def.Value);
  94. query.Set(def.Key, table);
  95. }
  96. }
  97. protected CoreTable InitializeTable(IQueryDef def)
  98. {
  99. var table = new CoreTable();
  100. if (def.Columns != null)
  101. table.LoadColumns(def.Columns);
  102. else
  103. table.LoadColumns(def.Type);
  104. return table;
  105. }
  106. protected class QueryStorage : ISerializeBinary
  107. {
  108. private Dictionary<String, CoreTable> _data = new Dictionary<string, CoreTable>();
  109. public CoreTable Get([NotNull] String key) => _data[key];
  110. public void Set([NotNull] String key, CoreTable table) => _data[key] = table;
  111. public bool Contains([NotNull] String key) => _data.ContainsKey(key);
  112. public void SerializeBinary(CoreBinaryWriter writer)
  113. {
  114. writer.Write(_data.Count);
  115. foreach (var key in _data.Keys)
  116. {
  117. writer.Write(key);
  118. _data[key].SerializeBinary(writer);
  119. }
  120. }
  121. public void DeserializeBinary(CoreBinaryReader reader)
  122. {
  123. int count = reader.ReadInt32();
  124. for (int i = 0; i < count; i++)
  125. {
  126. String key = reader.ReadString();
  127. CoreTable table = new CoreTable();
  128. table.DeserializeBinary(reader);
  129. _data[key] = table;
  130. }
  131. }
  132. }
  133. protected void LoadFromStorage(MultiQuery query)
  134. {
  135. QueryStorage storage = new QueryStorage();
  136. var file = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), FileName);
  137. if (File.Exists(file))
  138. {
  139. using (var stream = new FileStream(file, FileMode.Open))
  140. storage = Serialization.ReadBinary<QueryStorage>(stream, BinarySerializationSettings.Latest);
  141. var defs = query.Definitions();
  142. foreach (var key in defs.Keys)
  143. {
  144. var table = storage.Contains(key.ToString())
  145. ? storage.Get(key.ToString())
  146. : InitializeTable(defs[key]);
  147. query.Set(key, table);
  148. }
  149. }
  150. else
  151. InitializeTables(query);
  152. }
  153. protected void SaveToStorage(MultiQuery query)
  154. {
  155. QueryStorage storage = new QueryStorage();
  156. var results = query.Results();
  157. foreach (var key in results.Keys)
  158. storage.Set(key.ToString(),results[key]);
  159. var data = storage.WriteBinary(BinarySerializationSettings.Latest);
  160. try
  161. {
  162. var file = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), FileName);
  163. File.WriteAllBytes(file,data);
  164. }
  165. catch (Exception e)
  166. {
  167. MobileLogging.Log(e);
  168. }
  169. }
  170. }
  171. }