Binding
Object Hierarchy:
Description:
`GObject` instance (or source) and another property on another `GObject` instance (or target).
Whenever the source property changes, the same value is applied to the target property; for instance, the following binding:
```c g_object_bind_property (object1, "property-a", object2, "property-b", G_BINDING_DEFAULT); ```
will cause the property named "property-b" of object2
to be updated every time [method@GObject.set] or the specific accessor
changes the value of the property "property-a" of object1
.
It is possible to create a bidirectional binding between two properties of two `GObject` instances, so that if either property changes, the other is updated as well, for instance:
```c g_object_bind_property (object1, "property-a", object2, "property-b", G_BINDING_BIDIRECTIONAL); ```
will keep the two properties in sync.
It is also possible to set a custom transformation function (in both directions, in case of a bidirectional binding) to apply a custom transformation from the source value to the target value before applying it; for instance, the following binding:
```c g_object_bind_property_full (adjustment1, "value", adjustment2, "value", G_BINDING_BIDIRECTIONAL, celsius_to_fahrenheit, fahrenheit_to_celsius, NULL, NULL); ```
will keep the "value" property of the two adjustments in sync; the celsius_to_fahrenheit
function will be called whenever the
"value" property of adjustment1
changes and will transform the current value of the property before applying it to the "value"
property of adjustment2
.
Vice versa, the fahrenheit_to_celsius
function will be called whenever the "value" property of adjustment2
changes,
and will transform the current value of the property before applying it to the "value" property of adjustment1
.
Note that Binding does not resolve cycles by itself; a cycle like
``` object1GBinding:propertyA
-> object2GBinding:propertyB
object2GBinding:propertyB
-> object3
GBinding:propertyC
object3GBinding:propertyC
-> object1GBinding:propertyA
```
might lead to an infinite loop. The loop, in this particular case, can be avoided if the objects emit the `GObject:GBinding:notify
` signal only if the value has effectively been changed. A binding is implemented using the `GObject:GBinding:notify
` signal, so it
is susceptible to all the various ways of blocking a signal emission, like [func@GObject.signal_stop_emission] or [
func@GObject.signal_handler_block].
A binding will be severed, and the resources it allocates freed, whenever either one of the `GObject` instances it refers to are finalized, or when the Binding instance loses its last reference.
Bindings for languages with garbage collection can use [method@GObject.Binding.unbind] to explicitly release a binding between the source and target properties, instead of relying on the last reference on the binding, source, and target instances to drop.
Example: Property bindings:
public class ObjectA : Object {
public int property_a { get; set; }
public int property_b { get; set; }
public int property_c { get; set; }
public bool property_d { get; set; }
public int property_e { get; set; }
}
public class ObjectB : Object {
public int property_a { get; set; }
public int property_b { get; set; }
public int property_c { get; set; }
public bool property_d { get; set; }
public int property_e { get; set; }
}
public static int main (string[] args) {
// Objects:
ObjectA obja = new ObjectA ();
ObjectB objb = new ObjectB ();
//
// BindingFlags.DEFAULT:
//
print ("BindingFlags.DEFAULT:\n");
obja.property_a = 50;
objb.property_a = 60;
obja.bind_property ("property-a", objb, "property-a", BindingFlags.DEFAULT);
// Output: ``50 - 60``
print (" %d - %d\n", obja.property_a, objb.property_a);
// Output: ``10 - 10``
obja.property_a = 10;
print (" %d - %d\n", obja.property_a, objb.property_a);
// Output: ``10 - 15``
objb.property_a = 15;
print (" %d - %d\n", obja.property_a, objb.property_a);
//
// BindingFlags.BIDIRECTIONAL:
//
print ("BindingFlags.BIDIRECTIONAL:\n");
obja.property_b = 50;
objb.property_b = 60;
obja.bind_property ("property-b", objb, "property-b", BindingFlags.BIDIRECTIONAL);
// Output: ``50 - 60``
print (" %d - %d\n", obja.property_b, objb.property_b);
// Output: ``10 - 10``
obja.property_b = 10;
print (" %d - %d\n", obja.property_b, objb.property_b);
// Output: ``15 - 15``
objb.property_b = 15;
print (" %d - %d\n", obja.property_b, objb.property_b);
//
// BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL:
//
print ("BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL:\n");
obja.property_c = 50;
objb.property_c = 60;
obja.bind_property ("property-c", objb, "property-c", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL);
// Output: ``50 - 50``
print (" %d - %d\n", obja.property_c, objb.property_c);
// Output: ``10 - 10``
obja.property_c = 10;
print (" %d - %d\n", obja.property_c, objb.property_c);
// Output: ``20 - 20``
objb.property_c = 20;
print (" %d - %d\n", obja.property_c, objb.property_c);
//
// BindingFlags.INVERT_BOOLEAN:
//
print ("BindingFlags.INVERT_BOOLEAN:\n");
obja.property_d = false;
objb.property_d = true;
obja.bind_property ("property-d", objb, "property-d", BindingFlags.INVERT_BOOLEAN);
// Output: ``true - false``
obja.property_d = true;
print (" %s - %s\n", obja.property_d.to_string (), objb.property_d.to_string ());
// Output: ``false - true``
obja.property_d = false;
print (" %s - %s\n", obja.property_d.to_string (), objb.property_d.to_string ());
//
// Transformer:
//
print ("Transformer:\n");
obja.bind_property ("property-e", objb, "property-e", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL, (binding, srcval, ref targetval) => {
int src = (int) srcval;
targetval.set_int (src * 2);
return true;
}, (binding, srcval, ref targetval) => {
int src = (int) srcval;
targetval.set_int (src / 2);
return true;
});
obja.property_e = 50;
objb.property_e = 60;
// Output: ``30 - 60``
print (" %d - %d\n", obja.property_e, objb.property_e);
// Output: ``10 - 20``
obja.property_e = 10;
print (" %d - %d\n", obja.property_e, objb.property_e);
// Output: ``20 - 40``
objb.property_e = 40;
print (" %d - %d\n", obja.property_e, objb.property_e);
return 0;
}
valac --pkg gobject-2.0 GLib.Object.bind_property.vala