I agree with all you said but if in 2. you create an event dispatcher, you could do so as well in 4. Widgets are great using the observer pattern (if event X happens , do Y), which is in all cases better than creating a binding of text X to property Y. A delegate bound setter function to directly set a text on widget X avoids having a dupe text property and is more performant, since the widget doesn’t check for data every frame.
To be more literal, widgets are only created on the client in a networked game.
Hard reference itself is no downside? Everything is loaded in memory already and is expected to remain there.