Hi @stefano.menci,
Summary: You got to exactly the right solution in the end. To explain what you were seeing before, I ended up writing an in-depth explanation of data bindings. I’m including it here because it might be useful for others.
Just to restate the problem, as I understand it: You were using data-binding to set the item
property on a custom component. Within that custom component, you were either binding self.item
or self.item['foo']
to the text
property of a TextBox (with writeback switched on).
How data bindings work
Data bindings are actually very simple. If you set the binding on the self.component_1
's foo
property to SOME_EXPRESSION
, then when the refreshing_data_bindings
event triggers on your form, we execute:
self.component_1.foo = SOME_EXPRESSION
(Setting self.item = [anything]
on your form automatically triggers a data binding refresh; you can also do it manually with self.refresh_data_bindings()
.)
Writeback
If the foo
property is enabled for writeback, then when self.component_1
raises an event that triggers that writeback (eg a CheckBox’s change
event triggers writeback on its checked
property), we execute this:
SOME_EXPRESSION = self.component_1.foo
Worked example
My form has self.item
set to a row from the People table, which has a “name” column. I’ve got self.name_box
's text
bound to self.item['name']
, with writeback enabled.
- I set
self.item = person_row
. This triggers an automatic data-binding refresh. - The data binding runs:
self.name_box.text = self.item['name']
. The name appears in the text box. - I now edit the text box, and click away.
- The
lost_focus
event triggers data binding writeback on thetext
property of a TextBox - The data binding runs:
self.item['name'] = self.name_box.text
. This updates the database.
What happened in your original example
You had two data bindings. Inside your custom component, you’d bound self.text_box_1.text
to self.item
. (This is a little unconventional; traditionally self.item
is dict-like, but it won’t cause any problems.) Then, outside your custom component, you bound self.custom_component_1.item
to self.str_1
.
- You set up your form. The data binding duly writes the value of
self.str_1
toself.custom_component_1.item
- This triggers a data binding refresh within the custom component. It sets
self.custom_component_1.text_box_1.text
toself.custom_component_1.item
- You edit the textbox, and trigger data binding writeback
- The data binding runs:
self.custom_component_1.item = self.custom_component_1.text_box_1.text
. - …it stops here. There is no automatic mechanism to update the outer form’s
self.str_1
.
Aside: Why did this work when you used dicts? Because if two variables refer to the same dict
object, you can change it through one reference and view it through the other:
x = {'answer': 42}
y = x
y['answer'] = 43
print x['answer'] # Prints 43
So, if you’re setting a dict (or a database row) via data bindings, and you’re only updating keys in that dict (or columns in that DB), you don’t need writeback to make the new value available to outside code, because everyone is still looking at the same object. (You might still want an event so the outer form knows to update itself, but that’s a separate issue.)
As I said at the start, the solution you came to in the end is exactly the correct one. item
is a built-in property for all custom components, and it doesn’t support writeback. If you want to trigger writeback on a property of a custom component, you need to make a new property, enable it for write-back, and then make an event that triggers write-back for that property. (You have done all this - you’ve made a property called text
and an event called change
that triggers write-back for it.)