Binding JavaFX绑定设置器约定

Binding JavaFX绑定设置器约定,binding,javafx,javabeans,Binding,Javafx,Javabeans,我知道Java和C,但属性绑定我只知道C MVVM。 我试图理解JavaFX中的属性绑定,并为属性值定制getter和setter,如在C中 我创建了以下类: public class ViewModel { private StringProperty name; public ViewModel() { name = new SimpleStringProperty(); } public final String getName() {

我知道Java和C,但属性绑定我只知道C MVVM。 我试图理解JavaFX中的属性绑定,并为属性值定制getter和setter,如在C中

我创建了以下类:

public class ViewModel {

    private StringProperty name;

    public ViewModel() {
        name = new SimpleStringProperty();
    }

    public final String getName() {
        return name.get();
    }

    public final void setName(String name) {
        this.name.set(name);
    }

    public StringProperty getNameProperty() {
        return name;
    }
}

public class Controller implements Initializable {

    @FXML
    private TextField nameField;

    private final ViewModel viewModel;

    public Controller() {
        viewModel = new ViewModel();
    }

    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {
        Bindings.bindBidirectional(nameField.textProperty(),
                viewModel.getNameProperty());
    }
}
我的印象是,如果我遵循推荐的JavaBean/JavaFX命名约定,那么绑定系统将足够聪明,可以使用反射并为属性使用自定义的getter/setter。但是我的视图模型getter/setter从未被使用过

相反,绑定直接使用属性的get/set方法,而无需我的交互。 我读到我可以使用以下代码,但必须有比这更好的方法:

name = new SimpleStringProperty() {
    @Override public void set(String value) {
        // do something...
        super.set(value);
    }
};
我可以指定绑定应该使用哪些方法来获取/设置我的属性吗? 另一方面,我如何在不必更改的情况下,在C中通知属性已更改NotifyOfPropertyChange

编辑:

我试图做的是对最终设置到我的属性的内容进行更多的选择,因为我希望稍后使用它的值来填充这里省略的数据模型

在C语言中,这很简单,我只是在setter中设置了一个谓词。我可以通过设置其他属性来推动表单/向导的进度

public String Property {
    get { return _property; }
    set { 
        if(SomePredicate(value)) {
            _property = value;
            _nextButtonCommand.canExecute() = true;
            // notify...
        }
    }
}
JavaFX属性

在ViewModel类中定义name属性的约定是:

public class ViewModel {

    private StringProperty name;

    public ViewModel() {
        // parameters are owning bean, property name, and initial value, 
        // and are optional for the property convention
        name = new SimpleStringProperty(this, "name", "");
    }

    public final String getName() {
        return name.get();
    }

    public final void setName(String name) {
        this.name.set(name);
    }

    // Note this method name:
    public final StringProperty nameProperty() {
        return name;
    }
}
有一些变体:特别是如果您想使事物可重写,可以从nameProperty中删除最后一个修饰符,并在get和set方法中将this.name替换为this.nameProperty。关键是要确保调用setName。。。总是给出与nameProperty.set相同的结果。。。对于get方法也是如此

我认为你的一般解释有点偏离了一个层次,如果这有意义的话。该类定义了get和set方法,这些方法将因绑定而自动调用。因此,即使您有一个稍微不标准的命名约定,在文本字段中键入仍然会更新属性值。绑定API没有太多使用?据我所知,反射只是用属性注册监听器,并在另一个监听器发生变化时进行更新

至于自定义getter和setter,您展示的重写技术实际上只支持属性类。但是,我从来没有找到一个好的使用案例,尤其是绑定API,它让您有机会非常轻松地创建依赖值

更新

因此,对于您的具体示例,我将按照以下思路实现它:

public class ViewModel {
    private StringProperty name = new SimpleStringProperty(this, "name");
    // usual JavaFX Property methods...
}
然后,无论你在哪里需要它:

Predicate<String> predicate = ... ;
BooleanBinding canExecute = Bindings.createBooleanBinding(() -> 
    predicate.test(viewModel.getName()),
    viewModel.nameProperty());
如果谓词可能改变,您甚至可以这样做

ObjectProperty<Predicate<String>> predicate = new SimpleObjectProperty<>(s -> true);
BooleanBinding canExecute = Bindings.createBooleanBinding(() -> 
    predicate.get().test(viewModel.getName()),
    predicate, viewModel.nameProperty());
或者,在Java8中,要简洁得多

viewModel.nameProperty().addListener((obs, oldName, newName) -> 
    System.out.println("Name changed from "+oldValue+" to "+newValue));
只有当您有一个依赖于计算的ObservalEvalue时,无效侦听器和更改侦听器之间的差异才会变得明显。比较:

IntegerProperty x = new SimpleIntegerProperty(2);
IntegerProperty y = new SimpleIntegerProperty(3);
ObservableNumberValue sum = x.add(y);

sum.addListener(obs -> System.out.println("Invalidated")); // invalidation listener
x.set(3);
y.set(5);
使用相同的代码,但使用更改侦听器:

sum.addListener((obs, oldSum, newSum) -> System.out.println("Changed"));
而不是无效侦听器

更多详细信息请参见。

JavaFX属性

在ViewModel类中定义name属性的约定是:

public class ViewModel {

    private StringProperty name;

    public ViewModel() {
        // parameters are owning bean, property name, and initial value, 
        // and are optional for the property convention
        name = new SimpleStringProperty(this, "name", "");
    }

    public final String getName() {
        return name.get();
    }

    public final void setName(String name) {
        this.name.set(name);
    }

    // Note this method name:
    public final StringProperty nameProperty() {
        return name;
    }
}
有一些变体:特别是如果您想使事物可重写,可以从nameProperty中删除最后一个修饰符,并在get和set方法中将this.name替换为this.nameProperty。关键是要确保调用setName。。。总是给出与nameProperty.set相同的结果。。。对于get方法也是如此

我认为你的一般解释有点偏离了一个层次,如果这有意义的话。该类定义了get和set方法,这些方法将因绑定而自动调用。因此,即使您有一个稍微不标准的命名约定,在文本字段中键入仍然会更新属性值。绑定API没有太多使用?据我所知,反射只是用属性注册监听器,并在另一个监听器发生变化时进行更新

至于自定义getter和setter,您展示的重写技术实际上只支持属性类。但是,我从来没有找到一个好的使用案例,尤其是绑定API,它让您有机会非常轻松地创建依赖值

更新

因此,对于您的具体示例,我将按照以下思路实现它:

public class ViewModel {
    private StringProperty name = new SimpleStringProperty(this, "name");
    // usual JavaFX Property methods...
}
然后,无论你在哪里需要它:

Predicate<String> predicate = ... ;
BooleanBinding canExecute = Bindings.createBooleanBinding(() -> 
    predicate.test(viewModel.getName()),
    viewModel.nameProperty());
如果谓词可能改变,您甚至可以这样做

ObjectProperty<Predicate<String>> predicate = new SimpleObjectProperty<>(s -> true);
BooleanBinding canExecute = Bindings.createBooleanBinding(() -> 
    predicate.get().test(viewModel.getName()),
    predicate, viewModel.nameProperty());
或者,在Java8中,要简洁得多

viewModel.nameProperty().addListener((obs, oldName, newName) -> 
    System.out.println("Name changed from "+oldValue+" to "+newValue));
只有当您有一个依赖于计算的ObservalEvalue时,无效侦听器和更改侦听器之间的差异才会变得明显。比较:

IntegerProperty x = new SimpleIntegerProperty(2);
IntegerProperty y = new SimpleIntegerProperty(3);
ObservableNumberValue sum = x.add(y);

sum.addListener(obs -> System.out.println("Invalidated")); // invalidation listener
x.set(3);
y.set(5);
使用相同的代码,但使用更改侦听器:

sum.addListener((obs, oldSum, newSum) -> System.out.println("Changed"));
而不是无效侦听器


.

更新的答案中有更多详细信息,以响应编辑。我实际上喜欢覆盖属性集。说真的
在我的代码中,当我按照下面的答案执行时,setter永远不会被调用。我只使用FXML和我的模型来完成我的整个应用程序,但是我的控制器没有任何代码落后。更新答案以响应编辑。我实际上喜欢覆盖属性集。在我的代码中,由于某种原因,当我按照下面的答案执行时,setter从未被调用。我只使用FXML来完成我的整个应用程序,而我的控制器没有代码落后。