Deprecated API

Contents

  • Deprecated Interfaces
    Interface
    Description
    This contract is inherently unfriendly to both composition and thread safety, which is why it is replaced by the tuple based binding:
    • It forces an inheritance style contract onto your view models: every entry model must expose two mutable properties it usually does not care about, just to be displayable.
    • It is incompatible with the decoupled threading mode (see EventProcessor.DECOUPLED), by design: the UI thread writes into your view model while building an entry view and the view supplier immediately reads that state back. Since your view model belongs to the application thread, this mid-construction write/read handshake cannot be handed over to the application event queue without breaking it. Change listeners on EntryViewModel.isSelected() and EntryViewModel.position() will consequently run on the UI thread.

    The recommended alternative: tuple based binding

    Model your entries as a Var property holding an immutable Tuple of plain value objects which implement HasId (so that entry views can be recycled efficiently when the tuple changes). Any state an entry view needs, including its selection flag, is simply data in the value object:
    
        public record Entry(String id, String text, boolean selected)
        implements HasId<String>
        {
            public Entry withSelected( boolean selected ) {
                return new Entry(id, text, selected);
            }
        }
    
        Var<Tuple<Entry>> entries = Var.of(Tuple.of(
                                        new Entry("a", "Alpha", false),
                                        new Entry("b", "Beta",  true )
                                    ));
    
        UI.scrollPanels()
        .addAll(entries, entry ->  // <- every entry is exposed as a Var<Entry> lens
            UI.label(entry.viewAsString( e -> (e.selected() ? "> " : "") + e.text() ))
            .onMouseClick( it ->
                // Selecting one entry and deselecting all others is a single,
                // atomic tuple update, executed safely on the application thread:
                entries.update( tuple ->
                    tuple.map( e -> e.withSelected(e.id().equals(entry.get().id())) )
                )
            )
        )
      
    This dissolves the threading problem instead of merely patching it: there is no UI owned selection state to synchronize at all. The selection is owned by the application thread like any other view model state, exclusivity ("selecting one deselects the others") is one atomic tuple update, multi-selection and "no selection" fall out naturally, and because the entries are identified through HasId.id(), flipping a flag on an entry recycles its existing sub-view and channels the new state into it through its item property.

    The position of an entry is intentionally absent from this pattern: you assemble the tuple, so you already know where each entry sits, and you may store an index in your value objects if a view needs to display it.

    Note that this legacy interface remains functional in the coupled threading modes, but binding EntryViewModels in a UI declaration which uses the EventProcessor.DECOUPLED event processor will log a loud warning, because thread safety cannot be guaranteed for it.