Home > Mobile >  How to change a property binding during an element creation in QML?
How to change a property binding during an element creation in QML?

Time:01-30

Suppose I have a custom CheckBox:

//MyCheckBox.qml

CheckBox {
  required property QtObject proxy

  checked: proxy.value

  Binding {
    target:    proxy
    property:  "value"
    value:     checked
  }
}

So the checked status of the MyCheckBox bound to the value property of my object (proxy) and vise-versa, i.e. I have a two-way binding.

I am using my custom checkbox as follows:

//My window
Item {

  ...

  MyCheckBox {
    id:    ordinaryCheck
    proxy: ...
  }

  ...
}

Everything works as expected. But what if I need to invert the logic for some instance of MyCheckBox: when proxy.value is true the checkbox is unchecked, and when proxy.value is false the checkbox is checked ? But this, ofc, doesn't work as I have a binding loop here if I try to do this:

Item {

...

  MyCheckBox {
    id:    invertedCheck

    proxy:     ...
    checked:   !proxy.value

    Binding {
      target:    proxy.value
      property:  "value"
      value:     !checked
    }
}

The Qt bindings are also not an option:

//MyCheckBox.qml

CheckBox {
  required property QtObject proxy

  checked: proxy.value

  Component.onCompleted {
    property.value = Qt.binding(function() { return checked });
  }
}

I have the same binding loop error in this case.

So what is my option to reach the goal, how to alternate the binding at the moment of instantiation ?

CodePudding user response:

If you're concerned about a potential binding loop, it is a potential candidate to rewrite it as an imperative implementation, e.g.

CheckBox {
    required property QtObject proxy

    onCheckedChanged: {
        if (proxy && proxy.value !== checked) {
            proxy.value = checked;
        }
    }

    property bool proxyValue: proxy && proxy.value ? true : false

    onProxyValueChanged: {
        if (checked !== proxyValue) {
            checked = proxyValue;
        }
    }
}

CodePudding user response:

Your first version might also technically be a binding loop but is not detected as such.

You want to bind your checkbox value to your proxy value, and when the user toggles the checkbox you want to modify the proxy value.

To avoid binding loops, use specific interaction signals for each component, not generic onChanged signal. The former will fire only when the user interact with the UI, the latter will fire every time, even when the changes come from a backend change, leading to a potential binding loop. In your case you want the toggled signal:

//MyCheckBox.qml

CheckBox {
  required property QtObject proxy
  checked: proxy.value
  onToggled: proxy.value = checked
}

Note that this only works with QQC2 since they are not breaking the checked: proxy.value binding when the user toggles the checkbox, but still change the checked property value, hoping for an eventual resolution.

  • Related