diff --git a/src/net/Qml.Net.Tests/Qml/SignalTests.cs b/src/net/Qml.Net.Tests/Qml/SignalTests.cs index 9c55fff8..dcb61f06 100644 --- a/src/net/Qml.Net.Tests/Qml/SignalTests.cs +++ b/src/net/Qml.Net.Tests/Qml/SignalTests.cs @@ -31,6 +31,47 @@ namespace Qml.Net.Tests.Qml { } + + private string _someStringPropertyValue = ""; + + [NotifySignal] + public string SomeStringProperty + { + get => _someStringPropertyValue; + set { + if (_someStringPropertyValue == value) + return; + _someStringPropertyValue = value; + this.ActivateNotifySignal(); + } + } + + private int _someIntPropertyValue = 0; + + [NotifySignal("someWeirdSignalName")] + public int SomeIntProperty + { + get => _someIntPropertyValue; + set { + if (_someIntPropertyValue == value) + return; + _someIntPropertyValue = value; + this.ActivateNotifySignal(); + } + } + + private bool _someBoolPropertyValue = false; + + public bool SomeBoolProperty + { + get => _someBoolPropertyValue; + set { + if (_someBoolPropertyValue == value) + return; + _someBoolPropertyValue = value; + this.ActivateNotifySignal(); + } + } } [Signal("testSignal")] @@ -153,6 +194,75 @@ namespace Qml.Net.Tests.Qml Mock.VerifySet(x => x.SignalRaised = true, Times.Once); } + [Fact] + public void Can_raise_changed_default_signal_from_net() + { + Mock.Setup(x => x.SignalRaised).Returns(false); + + NetTestHelper.RunQml(qmlApplicationEngine, + @" + import QtQuick 2.0 + import tests 1.0 + ObjectTestsQml { + id: test + Component.onCompleted: function() { + test.someStringPropertyChanged.connect(function() { + test.signalRaised = true + }) + test.someStringProperty = 'NewValue' + } + } + "); + + Mock.VerifySet(x => x.SignalRaised = true, Times.Once); + } + + [Fact] + public void Can_raise_changed_custom_signal_from_net() + { + Mock.Setup(x => x.SignalRaised).Returns(false); + + NetTestHelper.RunQml(qmlApplicationEngine, + @" + import QtQuick 2.0 + import tests 1.0 + ObjectTestsQml { + id: test + Component.onCompleted: function() { + test.someWeirdSignalName.connect(function() { + test.signalRaised = true + }) + test.someIntProperty = 1 + } + } + "); + + Mock.VerifySet(x => x.SignalRaised = true, Times.Once); + } + + [Fact] + public void Can_not_raise_invalid_changed_signal_from_net() + { + Mock.Setup(x => x.SignalRaised).Returns(false); + + NetTestHelper.RunQml(qmlApplicationEngine, + @" + import QtQuick 2.0 + import tests 1.0 + ObjectTestsQml { + id: test + Component.onCompleted: function() { + test.someBoolPropertyChanged.connect(function() { + test.signalRaised = true + }) + test.someBoolProperty = true + } + } + "); + + Mock.VerifySet(x => x.SignalRaised = true, Times.Never); + } + [Fact] public void Can_raise_signal_from_net_with_args() { diff --git a/src/net/Qml.Net/Signals.cs b/src/net/Qml.Net/Signals.cs index 84bc59ad..3effcab0 100644 --- a/src/net/Qml.Net/Signals.cs +++ b/src/net/Qml.Net/Signals.cs @@ -1,4 +1,7 @@ -using Qml.Net.Internal; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; +using Qml.Net.Internal; using Qml.Net.Internal.Types; namespace Qml.Net @@ -34,6 +37,35 @@ namespace Qml.Net return true; } + /// + /// Activates the signal that has been attached to the given property using NotifySignalAttribute + /// + /// object instance having the property the changed signal has to be activated for + /// + /// 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. + /// true when the signal has been activated, otherwise false + 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(); + 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 void AttachToSignal(this object instance, string signalName, System.Delegate del) { instance.AttachDelegateToSignal(signalName, del);