Updating all view dispatchers to inherit from async dispatcher

This commit is contained in:
Nick Randolph 2018-04-03 16:40:26 +10:00
Родитель 8e88703683
Коммит 75c5764abf
17 изменённых файлов: 95 добавлений и 34 удалений

Просмотреть файл

@ -0,0 +1,18 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MS-PL license.
// See the LICENSE file in the project root for more information.
using System;
using System.Threading.Tasks;
namespace MvvmCross.Base
{
// Note: The long term goal should be to deprecate IMvxMainThreadDispatcher
// As such, even though the implementation of this interface also implements
// IMvxMainThreadDispatcher, this interface should not inherit from IMvxMainThreadDispatcher
public interface IMvxMainThreadAsyncDispatcher
{
Task ExecuteOnMainThreadAsync(Action action, bool maskExceptions = true);
Task ExecuteOnMainThreadAsync(Func<Task> action, bool maskExceptions = true);
}
}

Просмотреть файл

@ -9,12 +9,7 @@ namespace MvvmCross.Base
{ {
public interface IMvxMainThreadDispatcher public interface IMvxMainThreadDispatcher
{ {
[Obsolete("Use IMvxMainThreadAsyncDispatcher.ExecuteOnMainThreadAsync instead")]
bool RequestMainThreadAction(Action action, bool maskExceptions = true); bool RequestMainThreadAction(Action action, bool maskExceptions = true);
} }
public interface IMvxMainThreadAsyncDispatcher
{
Task<bool> ExecuteOnMainThreadAsync(Action action, bool maskExceptions = true);
Task<bool> ExecuteOnMainThreadAsync(Func<Task> action, bool maskExceptions = true);
}
} }

Просмотреть файл

@ -0,0 +1,43 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MS-PL license.
// See the LICENSE file in the project root for more information.
using System;
using System.Threading.Tasks;
namespace MvvmCross.Base
{
public abstract class MvxMainThreadAsyncDispatcher : MvxMainThreadDispatcher, IMvxMainThreadAsyncDispatcher
{
public Task ExecuteOnMainThreadAsync(Action action, bool maskExceptions = true)
{
var asyncAction = new Func<Task>(() =>
{
action();
return Task.CompletedTask;
});
return ExecuteOnMainThreadAsync(asyncAction, maskExceptions);
}
public async Task ExecuteOnMainThreadAsync(Func<Task> action, bool maskExceptions = true)
{
var completion = new TaskCompletionSource<bool>();
var syncAction = new Action(async () =>
{
await action();
completion.SetResult(true);
});
RequestMainThreadAction(syncAction, maskExceptions);
// If we're already on main thread, then the action will
// have already completed at this point, so can just return
if (completion.Task.IsCompleted)
return;
// Make sure we don't introduce weird locking issues
// blocking on the completion source by jumping onto
// a new thread to wait
await Task.Run(async () => await completion.Task);
}
}
}

Просмотреть файл

@ -4,12 +4,13 @@
using System; using System;
using System.Reflection; using System.Reflection;
using System.Threading.Tasks;
using MvvmCross.Exceptions; using MvvmCross.Exceptions;
using MvvmCross.Logging; using MvvmCross.Logging;
namespace MvvmCross.Base namespace MvvmCross.Base
{ {
public abstract class MvxMainThreadDispatcher : MvxSingleton<IMvxMainThreadDispatcher> public abstract class MvxMainThreadDispatcher : MvxSingleton<IMvxMainThreadDispatcher>, IMvxMainThreadDispatcher
{ {
protected static void ExceptionMaskedAction(Action action, bool maskExceptions) protected static void ExceptionMaskedAction(Action action, bool maskExceptions)
{ {
@ -34,5 +35,7 @@ namespace MvvmCross.Base
throw exception; throw exception;
} }
} }
public abstract bool RequestMainThreadAction(Action action, bool maskExceptions = true);
} }
} }

Просмотреть файл

@ -339,6 +339,7 @@ namespace MvvmCross.Core
{ {
var dispatcher = CreateViewDispatcher(); var dispatcher = CreateViewDispatcher();
Mvx.RegisterSingleton(dispatcher); Mvx.RegisterSingleton(dispatcher);
Mvx.RegisterSingleton<IMvxMainThreadAsyncDispatcher>(dispatcher);
Mvx.RegisterSingleton<IMvxMainThreadDispatcher>(dispatcher); Mvx.RegisterSingleton<IMvxMainThreadDispatcher>(dispatcher);
} }

Просмотреть файл

@ -10,9 +10,9 @@ using MvvmCross.Base;
namespace MvvmCross.Platforms.Android.Views namespace MvvmCross.Platforms.Android.Views
{ {
public class MvxAndroidMainThreadDispatcher : MvxMainThreadDispatcher public class MvxAndroidMainThreadDispatcher : MvxMainThreadAsyncDispatcher
{ {
public bool RequestMainThreadAction(Action action, bool maskExceptions = true) public override bool RequestMainThreadAction(Action action, bool maskExceptions = true)
{ {
if (Application.SynchronizationContext == SynchronizationContext.Current) if (Application.SynchronizationContext == SynchronizationContext.Current)
action(); action();

Просмотреть файл

@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements. // Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MS-PL license. // The .NET Foundation licenses this file to you under the MS-PL license.
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
@ -10,10 +10,10 @@ using MvvmCross.Views;
namespace MvvmCross.Platforms.Console.Views namespace MvvmCross.Platforms.Console.Views
{ {
public class MvxConsoleViewDispatcher public class MvxConsoleViewDispatcher
: MvxMainThreadDispatcher : MvxMainThreadAsyncDispatcher
, IMvxViewDispatcher , IMvxViewDispatcher
{ {
public bool RequestMainThreadAction(Action action, bool maskExceptions = true) public override bool RequestMainThreadAction(Action action, bool maskExceptions = true)
{ {
action(); action();
return true; return true;

Просмотреть файл

@ -11,7 +11,7 @@ using UIKit;
namespace MvvmCross.Platforms.Ios.Views namespace MvvmCross.Platforms.Ios.Views
{ {
public abstract class MvxIosUIThreadDispatcher public abstract class MvxIosUIThreadDispatcher
: MvxMainThreadDispatcher : MvxMainThreadAsyncDispatcher
{ {
private readonly SynchronizationContext _uiSynchronizationContext; private readonly SynchronizationContext _uiSynchronizationContext;
@ -22,7 +22,7 @@ namespace MvvmCross.Platforms.Ios.Views
throw new MvxException("SynchronizationContext must not be null - check to make sure Dispatcher is created on UI thread"); throw new MvxException("SynchronizationContext must not be null - check to make sure Dispatcher is created on UI thread");
} }
public bool RequestMainThreadAction(Action action, bool maskExceptions = true) public override bool RequestMainThreadAction(Action action, bool maskExceptions = true)
{ {
if (_uiSynchronizationContext == SynchronizationContext.Current) if (_uiSynchronizationContext == SynchronizationContext.Current)
action(); action();

Просмотреть файл

@ -12,7 +12,7 @@ using MvvmCross.Exceptions;
namespace MvvmCross.Platforms.Mac.Views namespace MvvmCross.Platforms.Mac.Views
{ {
public abstract class MvxMacUIThreadDispatcher public abstract class MvxMacUIThreadDispatcher
: MvxMainThreadDispatcher : MvxMainThreadAsyncDispatcher
{ {
private readonly SynchronizationContext _uiSynchronizationContext; private readonly SynchronizationContext _uiSynchronizationContext;
@ -23,7 +23,7 @@ namespace MvvmCross.Platforms.Mac.Views
throw new MvxException("SynchronizationContext must not be null - check to make sure Dispatcher is created on UI thread"); throw new MvxException("SynchronizationContext must not be null - check to make sure Dispatcher is created on UI thread");
} }
public bool RequestMainThreadAction(Action action, public override bool RequestMainThreadAction(Action action,
bool maskExceptions = true) bool maskExceptions = true)
{ {
if (_uiSynchronizationContext == SynchronizationContext.Current) if (_uiSynchronizationContext == SynchronizationContext.Current)

Просмотреть файл

@ -11,7 +11,7 @@ using UIKit;
namespace MvvmCross.Platforms.Tvos.Views namespace MvvmCross.Platforms.Tvos.Views
{ {
public abstract class MvxTvosUIThreadDispatcher public abstract class MvxTvosUIThreadDispatcher
: MvxMainThreadDispatcher : MvxMainThreadAsyncDispatcher
{ {
private readonly SynchronizationContext _uiSynchronizationContext; private readonly SynchronizationContext _uiSynchronizationContext;
@ -22,7 +22,7 @@ namespace MvvmCross.Platforms.Tvos.Views
throw new MvxException("SynchronizationContext must not be null - check to make sure Dispatcher is created on UI thread"); throw new MvxException("SynchronizationContext must not be null - check to make sure Dispatcher is created on UI thread");
} }
public bool RequestMainThreadAction(Action action, bool maskExceptions = true) public override bool RequestMainThreadAction(Action action, bool maskExceptions = true)
{ {
if (_uiSynchronizationContext == SynchronizationContext.Current) if (_uiSynchronizationContext == SynchronizationContext.Current)
action(); action();

Просмотреть файл

@ -8,7 +8,7 @@ using MvvmCross.Base;
namespace MvvmCross.Platforms.Uap.Views namespace MvvmCross.Platforms.Uap.Views
{ {
public class MvxWindowsMainThreadDispatcher : MvxMainThreadDispatcher public class MvxWindowsMainThreadDispatcher : MvxMainThreadAsyncDispatcher
{ {
private readonly CoreDispatcher _uiDispatcher; private readonly CoreDispatcher _uiDispatcher;
@ -17,7 +17,7 @@ namespace MvvmCross.Platforms.Uap.Views
_uiDispatcher = uiDispatcher; _uiDispatcher = uiDispatcher;
} }
public bool RequestMainThreadAction(Action action, bool maskExceptions = true) public override bool RequestMainThreadAction(Action action, bool maskExceptions = true)
{ {
if (_uiDispatcher.HasThreadAccess) if (_uiDispatcher.HasThreadAccess)
{ {

Просмотреть файл

@ -9,7 +9,7 @@ using MvvmCross.Base;
namespace MvvmCross.Platforms.Wpf.Views namespace MvvmCross.Platforms.Wpf.Views
{ {
public class MvxWpfUIThreadDispatcher public class MvxWpfUIThreadDispatcher
: MvxMainThreadDispatcher : MvxMainThreadAsyncDispatcher
{ {
private readonly Dispatcher _dispatcher; private readonly Dispatcher _dispatcher;
@ -18,7 +18,7 @@ namespace MvvmCross.Platforms.Wpf.Views
_dispatcher = dispatcher; _dispatcher = dispatcher;
} }
public bool RequestMainThreadAction(Action action, bool maskExceptions = true) public override bool RequestMainThreadAction(Action action, bool maskExceptions = true)
{ {
if (_dispatcher.CheckAccess()) if (_dispatcher.CheckAccess())
{ {

Просмотреть файл

@ -7,10 +7,10 @@ using MvvmCross.ViewModels;
namespace MvvmCross.Views namespace MvvmCross.Views
{ {
public interface IMvxViewDispatcher : IMvxMainThreadDispatcher public interface IMvxViewDispatcher : IMvxMainThreadDispatcher, IMvxMainThreadAsyncDispatcher
{ {
bool ShowViewModel(MvxViewModelRequest request); bool ShowViewModel(MvxViewModelRequest request);
bool ChangePresentation(MvxPresentationHint hint); bool ChangePresentation(MvxPresentationHint hint);
} }
} }

Просмотреть файл

@ -8,7 +8,7 @@ using MvvmCross.Base;
namespace MvvmCross.UnitTest.Mocks.Dispatchers namespace MvvmCross.UnitTest.Mocks.Dispatchers
{ {
public class CallbackMockMainThreadDispatcher public class CallbackMockMainThreadDispatcher
: MvxMainThreadDispatcher, IMvxMainThreadDispatcher : MvxMainThreadAsyncDispatcher
{ {
private readonly Func<Action, bool> _callback; private readonly Func<Action, bool> _callback;
@ -17,7 +17,7 @@ namespace MvvmCross.UnitTest.Mocks.Dispatchers
_callback = callback; _callback = callback;
} }
public virtual bool RequestMainThreadAction(Action action, public override bool RequestMainThreadAction(Action action,
bool maskExceptions = true) bool maskExceptions = true)
{ {
return _callback(action); return _callback(action);

Просмотреть файл

@ -8,11 +8,11 @@ using MvvmCross.Base;
namespace MvvmCross.UnitTest.Mocks.Dispatchers namespace MvvmCross.UnitTest.Mocks.Dispatchers
{ {
public class CountingMockMainThreadDispatcher public class CountingMockMainThreadDispatcher
: MvxMainThreadDispatcher, IMvxMainThreadDispatcher : MvxMainThreadAsyncDispatcher
{ {
public int Count { get; set; } public int Count { get; set; }
public bool RequestMainThreadAction(Action action, bool maskExceptions = true) public override bool RequestMainThreadAction(Action action, bool maskExceptions = true)
{ {
Count++; Count++;
return true; return true;

Просмотреть файл

@ -8,9 +8,9 @@ using MvvmCross.Base;
namespace MvvmCross.UnitTest.Mocks.Dispatchers namespace MvvmCross.UnitTest.Mocks.Dispatchers
{ {
public class InlineMockMainThreadDispatcher public class InlineMockMainThreadDispatcher
: MvxMainThreadDispatcher, IMvxMainThreadDispatcher : MvxMainThreadAsyncDispatcher
{ {
public virtual bool RequestMainThreadAction(Action action, public override bool RequestMainThreadAction(Action action,
bool maskExceptions = true) bool maskExceptions = true)
{ {
action(); action();

Просмотреть файл

@ -5,6 +5,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using MvvmCross.Base; using MvvmCross.Base;
using MvvmCross.Logging; using MvvmCross.Logging;
using MvvmCross.Tests; using MvvmCross.Tests;
@ -26,7 +27,7 @@ namespace MvvmCross.UnitTest.Mocks.Dispatchers
return true; return true;
} }
public virtual bool ShowViewModel(MvxViewModelRequest request) public virtual Task<bool> ShowViewModel(MvxViewModelRequest request)
{ {
var debugString = $"ShowViewModel: '{request.ViewModelType.Name}' "; var debugString = $"ShowViewModel: '{request.ViewModelType.Name}' ";
if (request.ParameterValues != null) if (request.ParameterValues != null)
@ -36,13 +37,13 @@ namespace MvvmCross.UnitTest.Mocks.Dispatchers
MvxTestLog.Instance.Log(MvxLogLevel.Debug, () => debugString); MvxTestLog.Instance.Log(MvxLogLevel.Debug, () => debugString);
Requests.Add(request); Requests.Add(request);
return true; return Task.FromResult(true);
} }
public virtual bool ChangePresentation(MvxPresentationHint hint) public virtual Task<bool> ChangePresentation(MvxPresentationHint hint)
{ {
Hints.Add(hint); Hints.Add(hint);
return true; return Task.FromResult(true);
} }
} }