Last active
June 11, 2019 01:57
-
-
Save alexshikov/0df2dfbbe55252fa6d2883b348d0ec68 to your computer and use it in GitHub Desktop.
MvxBundle extension to pass objects between ViewModel
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| public void OpenDetails () | |
| { | |
| var bundle = new MvxBundle (); | |
| bundle.WriteByTypeAsync (Place); // object type name is used as a stored key | |
| bundle.WriteBoolAsync(IsInMyGuides); // "System.Boolean" is used as a key | |
| ShowViewModel<PlaceViewModel>(bundle); | |
| } | |
| protected async override void InitFromBundle (IMvxBundle parameters) | |
| { | |
| base.InitFromBundle (parameters); | |
| // Load passed parameters | |
| Place = await parameters.ReadByTypeAsync<Place> ().ConfigureAwait (false); | |
| IsInMyGuides = await parameters.ReadBoolAsync ().ConfigureAwait (false); | |
| // Continue ViewModel loading | |
| await RunWithLoading (Load).ConfigureAwait (false); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| public static class MvxBundleExtensions | |
| { | |
| private const int StoreRecordsSize = 200; | |
| private const bool Verboose = false; | |
| private const string CachePrefix = "__bundle__"; | |
| private static long counter; | |
| public static Task WriteBoolAsync (this IMvxBundle bundle, bool value) | |
| { | |
| // boolean stored as integer | |
| // TODO use another key | |
| return WriteByTypeAsync(bundle, value == false ? 1 : 2); | |
| } | |
| public static Task WriteEnumAsync (this IMvxBundle bundle, object value) | |
| { | |
| var dict = new Dictionary<string, object> (); | |
| dict [value.GetType ().FullName] = value.ToString (); | |
| return WriteKeyValuesAsync(bundle, dict); | |
| } | |
| public static Task WriteKeyValuesAsync (this IMvxBundle bundle, Dictionary<string, object> dict) | |
| { | |
| if (dict == null || dict.Count == 0) { | |
| return Task.FromResult (false); | |
| } | |
| var cache = Mvx.Resolve<ICacheService> (); | |
| // Store keys, so that during the ReadAsync we know that the key is present, but the value is not stored yet | |
| foreach (var kvp in dict) | |
| { | |
| var key = kvp.Key; | |
| var value = kvp.Value; | |
| if (value != null) | |
| { | |
| var index = Interlocked.Increment (ref counter); | |
| if (index > StoreRecordsSize) | |
| { | |
| Interlocked.Exchange (ref counter, 0); | |
| index = 0; | |
| } | |
| var cacheKey = CachePrefix + index; | |
| cache.Clear (cacheKey); | |
| bundle.Data [key] = cacheKey; | |
| Trace ("Prepare to cache: {0}, {1}, {2}", key, cacheKey, value); | |
| } | |
| } | |
| // Serialization started on the new thread | |
| return Task.Factory.StartNew (() => { | |
| // TODO ICacheService implementation is out of the scope. It's possible to use in-memory | |
| var cacheService = Mvx.Resolve<ICacheService> (); | |
| var policy = new CachePolicy (TimeSpan.FromDays (1)); // TODO Do not limit lifetime | |
| foreach (var kvp in dict) | |
| { | |
| var key = kvp.Key; | |
| var value = kvp.Value; | |
| if (value != null) | |
| { | |
| cacheService.Put (bundle.Data [key], value, policy); | |
| Trace ("Cached: {0}, {1}", bundle.Data[key], value); | |
| } | |
| } | |
| }); | |
| } | |
| public static Task WriteByTypeAsync (this IMvxBundle bundle, params object[] values) | |
| { | |
| if (values == null || values.Length == 0) { | |
| return Task.FromResult (false); | |
| } | |
| var dict = new Dictionary<string, object> (); | |
| foreach (var value in values) | |
| { | |
| if (value != null) | |
| { | |
| dict [value.GetType ().FullName] = value; | |
| } | |
| } | |
| return WriteKeyValuesAsync (bundle, dict); | |
| } | |
| public static async Task<bool> ReadBoolAsync (this IMvxBundle bundle) | |
| { | |
| var intResult = await ReadByTypeAsync<int>(bundle); | |
| return (intResult != 0 && intResult != 1); | |
| } | |
| public static async Task<T> ReadEnumAsync<T> (this IMvxBundle bundle) | |
| where T: struct | |
| { | |
| var valueAsString = await ReadByKeyAsync<string>(bundle, typeof (T).FullName); | |
| T value; | |
| return Enum.TryParse<T> (valueAsString, out value) ? value : default (T); | |
| } | |
| public static Task<T> ReadByTypeAsync<T> (this IMvxBundle bundle) | |
| { | |
| return ReadByKeyAsync<T> (bundle, typeof(T).FullName); | |
| } | |
| public static Task<T> ReadByKeyAsync<T> (this IMvxBundle bundle, string key) | |
| { | |
| Trace ("Looking for: {0}", key); | |
| return Task.Factory.StartNew (() => { | |
| string cacheKey; | |
| object result = null; | |
| if (bundle.Data.TryGetValue (key, out cacheKey)) | |
| { | |
| var cacheService = Mvx.Resolve<ICacheService> (); | |
| result = cacheService.Get<T> (cacheKey).Result; | |
| Trace ("Waiting for: {0}, {1}", key, cacheKey); | |
| var t = DateTime.Now; | |
| while (IsResultNull<T> (result) && (DateTime.Now - t) < TimeSpan.FromSeconds (10)) | |
| { | |
| Task.Delay (20).Wait (); | |
| result = cacheService.Get<T> (cacheKey).Result; | |
| } | |
| //cacheService.Clear (cacheKey); | |
| } | |
| Trace ("Result: {0}, {1}, {2}", key, cacheKey, result); | |
| return IsResultNull<T> (result) | |
| ? default (T) | |
| : (T)result; | |
| }); | |
| } | |
| private static bool IsResultNull<T> (object result) | |
| { | |
| if (result == null) { | |
| return true; | |
| } | |
| if (result is Enum) { | |
| return false; | |
| } | |
| return object.Equals (result, default(T)); | |
| } | |
| private static void Trace (string format, params object[] args) | |
| { | |
| if (Verboose) | |
| { | |
| System.Diagnostics.Debug.WriteLine ("--- " + format, args); | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment