Ensuring UI thread. Making it optional.

This commit is contained in:
Paul Knopf 2019-03-23 18:07:47 -04:00
parent 53d6189d11
commit 178648fc27
7 changed files with 60 additions and 28 deletions

View file

@ -9,6 +9,7 @@ namespace Qml.Net.Tests
protected BaseTests()
{
QmlNetConfig.ShouldEnsureUIThread = false; // Not need for unit tests.
Monitor.Enter(LockObject);
}

View file

@ -245,12 +245,12 @@ namespace Qml.Net.Internal
}
var result = componentCompelted.ComponentCompleted();
if (Tasks.ListenForExceptionsWhenInvokingTasks)
if (QmlNetConfig.ListenForExceptionsWhenInvokingTasks)
{
result?.ContinueWith(
task =>
{
Tasks.RaiseUnhandledTaskException(task.Exception);
QmlNetConfig.RaiseUnhandledTaskException(task.Exception);
},
TaskContinuationOptions.OnlyOnFaulted);
}
@ -344,12 +344,12 @@ namespace Qml.Net.Internal
Task resultTask = null;
del(target, parameters, result, ref resultTask);
if (Tasks.ListenForExceptionsWhenInvokingTasks)
if (QmlNetConfig.ListenForExceptionsWhenInvokingTasks)
{
resultTask?.ContinueWith(
task =>
{
Tasks.RaiseUnhandledTaskException(task.Exception);
QmlNetConfig.RaiseUnhandledTaskException(task.Exception);
},
TaskContinuationOptions.OnlyOnFaulted);
}

View file

@ -25,6 +25,7 @@ namespace Qml.Net.Internal.Types
{
return obj;
}
throw new InvalidOperationException($"No object found for object id {ObjectId}");
}
}
@ -33,6 +34,8 @@ namespace Qml.Net.Internal.Types
public bool ActivateSignal(string signalName, params object[] parameters)
{
QmlNetConfig.EnsureUIThread();
if (parameters != null && parameters.Length > 0)
{
using (var list = new NetVariantList())
@ -45,6 +48,7 @@ namespace Qml.Net.Internal.Types
list.Add(variant);
}
}
return Interop.NetReference.ActivateSignal(Handle, signalName, list.Handle) == 1;
}
}

View file

@ -16,7 +16,7 @@ namespace Qml.Net
private GCHandle _triggerHandle;
private GCHandle _aboutToQuitHandle;
private readonly List<AboutToQuitEventHandler> _aboutToQuitEventHandlers = new List<AboutToQuitEventHandler>();
private static int _threadId;
private static int? _threadId;
protected QCoreApplication(IntPtr handle, bool ownsHandle)
: base(handle, ownsHandle)
@ -66,7 +66,18 @@ namespace Qml.Net
SynchronizationContext.SetSynchronizationContext(new QtSynchronizationContext(this));
}
public static bool IsMainThread => Environment.CurrentManagedThreadId == _threadId;
public static bool IsMainThread
{
get
{
if (!_threadId.HasValue)
{
throw new Exception("QCoreApplication hasn't been created yet, can't determine what thread is the main thread.");
}
return Environment.CurrentManagedThreadId == _threadId;
}
}
public int Exec()
{

View file

@ -0,0 +1,38 @@
using System;
namespace Qml.Net
{
public class QmlNetConfig
{
public static bool ListenForExceptionsWhenInvokingTasks { get; set; }
public static event Action<AggregateException> UnhandledTaskException;
internal static void RaiseUnhandledTaskException(AggregateException ex)
{
var handler = UnhandledTaskException;
handler?.Invoke(ex);
}
public static bool ShouldEnsureUIThread { get; set; } = true;
public static Action EnsureUIThreadDelegate = () =>
{
if (QCoreApplication.IsMainThread)
{
throw new Exception(
"You must be on the UI thread to perform this task. See https://github.com/qmlnet/qmlnet/issues/112");
}
};
internal static void EnsureUIThread()
{
if (!ShouldEnsureUIThread)
{
return;
}
EnsureUIThreadDelegate?.Invoke();
}
}
}

View file

@ -13,11 +13,6 @@ namespace Qml.Net
{
public static bool ActivateSignal(this object instance, string signalName, params object[] args)
{
if (!QCoreApplication.IsMainThread)
{
throw new Exception("An attempt was made to activate a signal from a non-UI thread.");
}
var existing = NetReference.CreateForObject(instance, false /*Ignore if not tagged*/);
if (existing != null && existing.ActivateSignal(signalName, args))
{

View file

@ -1,17 +0,0 @@
using System;
namespace Qml.Net
{
public static class Tasks
{
public static bool ListenForExceptionsWhenInvokingTasks { get; set; }
public static event Action<AggregateException> UnhandledTaskException;
internal static void RaiseUnhandledTaskException(AggregateException ex)
{
var handler = UnhandledTaskException;
handler?.Invoke(ex);
}
}
}