QML - signals for nested properties



  • If I have property var name; then I can use the onName signal to know when it's changed. But what about when a property is nested inside another object, what is the syntax for that?



  • @Vadi2 The right signal name is onNameChanged, but I don't really understand your question. Can you have a small QML code extract to show what you want to do?



  • I have an object that I populate from the backend (in this case - I'm learning C# and QML at once, so the backend is in C#). What I have in QML is:

    AppModel {
        id: appmodel
    }
    

    (for the curious - it's populated from C# here)

    I can then use various properties such as appmodel.scopeDirectory, appmodel.resourceText, appmodel.dotnetResult.errorCount and so on.

    How can I trigger on appmodel.dotnetResult.errorCount changing is my exact question?



  • @Vadi2 I still don't really understand what you want to achieve... Why do you have a C# part? do you use Qml.Net?

    What do you want to do? Is it inside AppModel component? What is AppModel?

    If you want to made public and internal state, you can do something like this, in AppModel.qml, I suppose AppModel is base on Item:

    import QtQuick 2.4
    
    Item {
    ...
        property alias errorCount: dotnetResult.errorCount
    
    }
    


  • Yep, I'm using Qml.Net!

    AppModel is a component I register in C# (https://github.com/vadi2/Hammer/blob/master/Program.cs#L628), this is similar to how you register a custom component from C++ I think.

    I don't have an AppModel.qml, but I'll try the property aliases anyway...



  • @Vadi2 Sorry, I don't think I can help you. I never used Qml.Net and don't know what is the best way to achieve this.


  • Qt Champions 2018

    If your sub properties are correctly typed, you can do that:

    AppModel {
        id: appmodel
        dotNetResult.onErrorCountChanged: print("error count changed")
    }
    

    If the dotNetResult is a generic type (I assume it would be a QObject*, a QQmlPropertyMap* or a QVariantMap), this won't work because there is no errorCountChanged signal in the base type, even if the actual instance has one.

    A solution in this case would be to use Connections :

    Connections {
        target: appmodel.dotNetResult
        onErrorCountChanged: print("error count changed")
    }
    


  • @GrecKo said in QML - signals for nested properties:

    If your sub properties are correctly typed

    I guess they're not, it says Cannot assign to non-existent property "dotNetResult". I see that Connections doc says they're useful for Connecting to targets not defined in QML which is perhaps the case here.

    It didn't work either unfortunately:

    file:///home/vadi/Programs/Hammer/Main.qml:382:29: QML Connections: Cannot assign to non-existent property "onErrorCountChanged"
    file:///home/vadi/Programs/Hammer/Main.qml:383:33: Unable to assign [undefined] to QObject*
    

    From reading the doc, I can put it anywhere, right?


  • Qt Champions 2018

    @Vadi2
    is Main.qml:383:33: Unable to assign [undefined] to QObject* refering to the line with target: appmodel.dotNetResult?
    Can you show us how you used Connections?

    You should be able to use Connections anywhere yes.



  • I did it both deep down in a component where I actually use appmodel.dotNetResult.errorCount successfully and at the root level:

        AppModel {
            id: appmodel
        }
    
        Connections {
            target: appmodel.dotNetResult
            onErrorCountChanged: print("error count changed")
    
            Component.onCompleted: appmodel.testMe()
        }
    

    Root level use says:

    file:///home/vadi/Programs/Hammer/Main.qml:25:5: QML Connections: Cannot assign to non-existent property "onErrorCountChanged"
    Writing test - errorcount is 0
    file:///home/vadi/Programs/Hammer/Main.qml:26:9: Unable to assign [undefined] to QObject*
    

    I also defined a TestMe() method which prints this:

        public void TestMe()
        {
          Console.WriteLine($"Writing test - errorcount is {DotnetResult.ErrorCount}");
        }
    

    So we can be pretty certain the property does exist and is filled in...


  • Qt Champions 2018

    @Vadi2 said in QML - signals for nested properties:

    Unable to assign [undefined] to QObject*

    That errors means appmodel.dotNetResult is undefined, the property might incorrectly be exposed.

    Your TestMe() test only shows that DotnetResult.ErrorCount is accessible from C#, not that it is properly exposed to QML.



  • Aha we had a typo, it should be dotnetResult and not dotNetResult. Fixing the typo so the code becomes:

        AppModel {
            id: appmodel
        }
    
        Connections {
            target: appmodel.dotnetResult
            onErrorCountChanged: print("error count changed")
    
            Component.onCompleted: { appmodel.testMe(); console.log(`errors: ${appmodel.dotnetResult.errorCount}`) }
        }
    

    I get the following output:

    Writing test - errorcount is 0
    qml: errors: 0
    

    But no notification of the change.

    I _am_replacing DotnetResult in C# with another validation result when I get it - perhaps I shouldn't replace the object but copy/set the properties instead. I'll try it.



  • No, the object replacing theory wasn't in. Before I do any validation, so appmodel.dotnetResult stays as-is, still don't get a notification with the following code:

        AppModel {
            id: appmodel
        }
    
        Connections {
            target: appmodel.dotnetResult
            onErrorCountChanged: print("error count changed")
    
            Component.onCompleted: { appmodel.testMe(); console.log(`errors: ${appmodel.dotnetResult.errorCount}`) }
        }
    
        Timer {
            interval: 1000; running: true;
            onTriggered: { appmodel.testMe(); console.log(`errors: ${appmodel.dotnetResult.errorCount}`) }
        }
    

    Output:

    Writing test - errorcount is 8
    qml: errors: 8
    Writing test - errorcount is 6
    qml: errors: 6
    

    So the properties are accessible - but not able to be notified correctly. What techniques can I use to debug this?


Log in to reply