-
Notifications
You must be signed in to change notification settings - Fork 106
/
Signals.cs
97 lines (87 loc) · 3.92 KB
/
Signals.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using Qml.Net.Internal;
using Qml.Net.Internal.Types;
namespace Qml.Net
{
public static class Signals
{
public static bool ActivateSignal(this object instance, string signalName, params object[] args)
{
var existing = NetReference.CreateForObject(instance, false /*Ignore if not tagged*/);
if (existing != null && existing.ActivateSignal(signalName, args))
{
// This means the the instance was alive in Qml, and the signal was
// activated. We don't have to store in signals stored in .NET
// because when the instance is sent to Qml, any delegates associated
// with the .NET object are auto-attached to correct signals.
// So, nothing to do here, because all the .NET delegates were raised
// elsewhere!
return true;
}
var signals = instance.GetAttachedDelegates(signalName);
if (signals == null || signals.Count <= 0)
{
return false;
}
foreach (var del in signals)
{
del.DynamicInvoke(args);
}
return true;
}
/// <summary>
/// Activates the signal that has been attached to the given property using NotifySignalAttribute
/// </summary>
/// <param name="instance">object instance having the property the changed signal has to be activated for</param>
/// <param name="propertyName">
/// name of the property. Gets automatically filled with the caller member name.
/// So calling it directly out of the property that is tied to the signal doesn't need to set this parameter explicitly.</param>
/// <returns>true when the signal has been activated, otherwise false</returns>
public static bool ActivateNotifySignal(this object instance, [CallerMemberName] string propertyName = "")
{
if (instance == null)
return false;
var propertyInfo =
instance.GetType().GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public);
if (propertyInfo == null)
return false;
var notifySignalAttributes = propertyInfo.GetCustomAttributes().OfType<NotifySignalAttribute>();
var notifySignalAttribute = notifySignalAttributes.FirstOrDefault();
if (notifySignalAttribute == null)
return false;
var signalName = notifySignalAttribute.Name;
if (string.IsNullOrEmpty(signalName))
{
signalName = $"{propertyInfo.Name}Changed";
signalName = char.ToLower(signalName[0]) + signalName.Substring(1);
}
return ActivateSignal(instance, signalName);
}
public static bool SetProperty<T>(this object instance, ref T storage, T value, [CallerMemberName] string propertyName = "")
{
if (EqualityComparer<T>.Default.Equals(storage, value))
return false;
storage = value;
instance.ActivateNotifySignal(propertyName);
return true;
}
public static bool ActivateProperty<T, TProperty>(this T instance, Expression<Func<T, TProperty>> expression)
{
var propExpression = expression.Body as MemberExpression;
if (propExpression == null)
{
throw new Exception("Invalid expression");
}
return ActivateNotifySignal(instance, propExpression.Member.Name);
}
public static void AttachToSignal(this object instance, string signalName, System.Delegate del)
{
instance.AttachDelegateToSignal(signalName, del);
}
}
}