Java ListView setCellFactory会弄乱绑定,除非匿名内部类?

Java ListView setCellFactory会弄乱绑定,除非匿名内部类?,java,listview,javafx,custom-cell,anonymous-inner-class,Java,Listview,Javafx,Custom Cell,Anonymous Inner Class,为什么在将JavaFX回调实例传递给ListView::setCellFactory以绑定selectedItemProperty(属于ListView::getSelectionModel)时,我需要对其进行匿名子类化,以便在selectedItemProperty更改时实际收到通知 好的,我克隆了james-d的嵌套控制器示例: 我想知道为什么在用这个最小的代码替换MainController.java的personList.setCellFactory行时,编辑器的绑定仍然有效(单元格为空

为什么在将JavaFX回调实例传递给
ListView::setCellFactory
以绑定
selectedItemProperty
(属于
ListView::getSelectionModel
)时,我需要对其进行匿名子类化,以便在
selectedItemProperty
更改时实际收到通知

好的,我克隆了james-d的嵌套控制器示例:

我想知道为什么在用这个最小的代码替换
MainController.java
personList.setCellFactory
行时,编辑器的绑定仍然有效(单元格为空,但编辑器的绑定仍然有效)

我发现,当使用自定义的
ListCellFactory
(其中每个
ListCell
textProperty
都被绑定并正确显示)时,同样的问题仍然存在,因此问题不在于实现本身(某种程度上),而在于如何实例化传递给setCellFactory的回调参数,wich显然必须是一个匿名子类,具有selectedItemProperty的绑定才能按预期工作(谁知道还有什么可能会受到影响)

不起作用:

作品:

有人能复制这个问题吗

在工厂的情况下,实现了
textProperty
绑定,因此并非如此,但无论如何,
PersonListCellFactory的代码如下:

package nestedcontrollerexample;

import javafx.beans.binding.Bindings;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.util.Callback;

public class PersonListCellFactory implements Callback<ListView<Person>, ListCell<Person>> {
    @Override
    public ListCell<Person> call(ListView<Person> param) {
        return new ListCell<Person>() {
            @Override
            public void updateItem(Person person, boolean empty) {
                super.updateItem(person, empty);
                textProperty().unbind();
                if (person != null) {
                    textProperty().bind(Bindings.format("%s %s", person.firstNameProperty(), person.lastNameProperty()));
                }
            }
        };
    }
}
包嵌套控制器示例;
导入javafx.beans.binding.Bindings;
导入javafx.scene.control.ListCell;
导入javafx.scene.control.ListView;
导入javafx.util.Callback;
公共类PersonListCellFactory实现回调{
@凌驾
公共ListCell调用(ListView参数){
返回新的ListCell(){
@凌驾
public void updateItem(Person,布尔值为空){
super.updateItem(person,空);
textProperty().unbind();
if(person!=null){
textProperty().bind(Bindings.format(“%s%s”、person.firstNameProperty()、person.lastNameProperty());
}
}
};
}
}

那么这怎么可能呢?

您提供的单元格工厂在单元格显示的当前项的
nameProperty
和单元格文本之间建立了绑定。这意味着当项目名称更改时,单元格将收到通知并更新其文本

如果没有此绑定,即使编辑器中的文本字段仍然绑定到项目中的属性,如果属性发生更改,单元格也不知道要更新。因此,简而言之,编辑器和列表项之间的绑定仍然有效,但是列表项没有通知显示文本的单元格

如果在UI中添加一个按钮,该按钮的操作处理程序

myItemList.getItems().forEach(System.out::println);
您将看到,更改文本字段中的文本确实会更新基础模型,只是单元格尚未更新

您可以通过使用带提取器的列表来修复此问题:另请参见。这使列表能够在模型类的某些属性更改时触发更新通知(列表视图可以看到这些通知,因此它会更新相关单元格)。在你的情况下,你需要

public void initialize() {
    myItemList.setItems(FXCollections.observableArrayList(item -> 
        new Observable[]{item.nameProperty()}));
    myItemList.getItems().addAll(sampleMyItems());

    myItemEditorController.myItemProperty().bind(myItemList.getSelectionModel().selectedItemProperty());
}

您提供的单元格工厂在单元格显示的当前项的
nameProperty
与单元格文本之间建立绑定。这意味着当项目名称更改时,单元格将收到通知并更新其文本

如果没有此绑定,即使编辑器中的文本字段仍然绑定到项目中的属性,如果属性发生更改,单元格也不知道要更新。因此,简而言之,编辑器和列表项之间的绑定仍然有效,但是列表项没有通知显示文本的单元格

如果在UI中添加一个按钮,该按钮的操作处理程序

myItemList.getItems().forEach(System.out::println);
您将看到,更改文本字段中的文本确实会更新基础模型,只是单元格尚未更新

您可以通过使用带提取器的列表来修复此问题:另请参见。这使列表能够在模型类的某些属性更改时触发更新通知(列表视图可以看到这些通知,因此它会更新相关单元格)。在你的情况下,你需要

public void initialize() {
    myItemList.setItems(FXCollections.observableArrayList(item -> 
        new Observable[]{item.nameProperty()}));
    myItemList.getItems().addAll(sampleMyItems());

    myItemEditorController.myItemProperty().bind(myItemList.getSelectionModel().selectedItemProperty());
}

如果没有
MyItemListCellFactory
的实现,我想回答#3是不可能的。我猜您有一个
ListCell
实现,它不会更新它的
item
属性(就像在您的示例中调用
super.updateItem()
时所做的那样),因此列表视图不知道该项(它轮询所选的
ListCell
以获取它的
item
属性),如果删除单元工厂,编辑器控制器和选定项之间的绑定仍然存在。问题是,当您更改文本字段中的文本时,列表单元格无法知道如何更新单元格。(列表中项目的属性发生更改,但列表本身没有更改。)您可以使用来更新列表视图。请注意,即使没有提取器,如果您使用
System.out.println(personList.getItems())
它也可以工作。我测试了用独立类替换lambda,这似乎很好。这很奇怪..:匿名类可以工作personList.setCellFactory(新回调(){@Override public ListCell call(ListView ListView){return new ListCell();}}});仍然有效,但如果我用lambda:personList.setCellFactory(ListView->new ListCell())替换它;WTF不工作?!第一个不工作;所有单元格都是空的。也许你的项目没有重建?如果没有实现
MyItemListCellFactory
,我想你不可能回答#3。我猜你有一个
ListCell
实现
myItemList.getItems().forEach(System.out::println);
public void initialize() {
    myItemList.setItems(FXCollections.observableArrayList(item -> 
        new Observable[]{item.nameProperty()}));
    myItemList.getItems().addAll(sampleMyItems());

    myItemEditorController.myItemProperty().bind(myItemList.getSelectionModel().selectedItemProperty());
}