JavaFX 绑定 UI 到嵌套的 class 的 属性

JavaFX Bind UI to a nested class's property

我有一个名为 Passage 的 class,其中包含一个名为 Action 的不可观察的 class。 Action 包含一个 SimpleStringProperty.

class Passage {

    Action action = null;

    Action getAction() { return action; }

    void setAction(Action action) { this.action = action; }

    boolean hasAction() { return action != null; }
}

class Action {

    StringProperty myStringProperty = new SimpleStringProperty();

    StringProperty getStringProperty() { return myStringProperty; }

    // and other methods, many of which modify myStringProperty
}

我想将该字符串 属性 绑定到 UI 标签。看起来应该是一件简单的事情:

label.textProperty.bind(passage.getAction().getStringProperty());

但是,Action 有时可能为空。我尝试了以下方法:

label.textProperty.bind(passage.hasAction() ? passage.getAction().getStringProperty() : new SimpleStringProperty("") );

然后,如果 Action 开始为空(因此标签开始为空),然后将 Action 分配给非空的东西(即调用 setAction()),则标签不会更新以反映更改.

我需要让 Action 可见吗?参见:

上面的解决方案使用了我不熟悉的单子操作。所以我阅读了这个有用的博客 post:http://tomasmikula.github.io/blog/2014/03/26/monadic-operations-on-observablevalue.html

我已经尝试使用 EasyBind 进行此绑定。

我创建了一个新的 class ObservableAction 来包装一个 Action,使它成为一个可观察的值(虽然我不确定我是否正确地完成了这一步):

import javafx.beans.binding.ObjectBinding;

public class ObservableAction extends ObjectBinding <Action>
{
    private final Action value;

    public ObservableAction(Action action) {
        this.value = action;
    }

    @Override
    public Action computeValue()
    {
        return value;
    }
}

然后我的 ViewController 中有以下代码(同样,不确定我是否正确执行此操作):

MonadicObservableValue<Action> monadicAction = EasyBind.monadic(new ObservableAction(passage.getAction()));

actionLabel.textProperty().bind(monadicAction.flatMap(action -> action.getTextProperty()).orElse(""));

结果和我以前经历过的一样:当 Action 不为空时它工作正常。但是,如果 Action 开始为空然后变为非空,则不会更新标签。

我建议在 Passage 中添加一个 属性,它将与动作的 属性 绑定。 一旦你设置了一个新的动作,你就绑定它 属性 并且只使用 Passage 的一个。

class Passage {
    private Action action;

    private StringProperty actionMyStringProperty = new SimpleStringProperty();

    void setAction(Action action) {
        this.action = action;

        // Unbind the previous binding if any (it is safe when nothing to unbind).
        actionMyStringProperty.unbind();

        if (action != null){
            actionMyStringProperty.bind(action.getStringProperty());
        }
    }

    public StringProperty actionMyStringProperty() {
        return actionMyStringProperty;
    }
}

class Action {
    private StringProperty myStringProperty = new SimpleStringProperty();

    StringProperty getStringProperty() {
        return myStringProperty;
    }
}

在客户端:

label.textProperty.bind(passage.actionMyStringProperty());