Skip to content

Instantly share code, notes, and snippets.

@alexshikov
Last active June 11, 2019 01:57
Show Gist options
  • Select an option

  • Save alexshikov/0df2dfbbe55252fa6d2883b348d0ec68 to your computer and use it in GitHub Desktop.

Select an option

Save alexshikov/0df2dfbbe55252fa6d2883b348d0ec68 to your computer and use it in GitHub Desktop.
MvxBundle extension to pass objects between ViewModel
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);
}
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