2

我正在使用 GWT 2.5.0

我的意图是创建一个绑定到ParentBean对象的编辑器层次结构。ParentBean包含 a List<Group>,而beanGroup有 aList<ChildBean>List<Group>。从我发现的编辑器教程中,创建一个包含 ListEditor 作为其子编辑器之一的编辑器似乎很简单。但父编辑器似乎从未正确初始化子 ListEditor。

这是我如何尝试执行此操作的解释。

从下面的代码中,我创建了一个ParentBeanEditor由另一个编辑器组成的GroupListEditor. 工具。
_ 然后,包含一个子编辑器和一个.GroupListEditorIsEditor<ListEditor<Group, GroupEditor>>
GroupEditorGroupListEditorChildBeanEditor

ParentBeanEditor我用ParentBean包含对象列表的a初始化了Group,但GroupEditor从未为任何Group对象构造过。
我在方法中放置了断点EditorSource<GroupEditor>.create(int)以验证s 中的每个都GroupEditor被创建,但断点从未被命中(ListEditor 没有构造编辑器)。GroupParentBean

我预计GroupListEditor会被初始化,因为它是ParentBeanEditor. 列表和编辑器链都没有设置在GroupListEditor. 我试图通过扩展来GroupListEditor直接设置子编辑器的列表。这样做,我上面提到的断点被击中,并试图将 a 附加到编辑器链。但是编辑器链从未设置,并且在第 95 行抛出了 NPE。ParentBeanEditorValueAwareEditor<ParentBean>GroupListEditorGroupEditorListEditorWrapper

例子

这是GroupListEditor未按预期初始化的示例。永远不会设置,这EditorChain会导致在ListEditorWrapper第 95 行抛出 NPE。

数据模型

public interface ParentBean {
    ...
    List<Group> getGroups();
}

public interface Group {
    ...
    List<ChildBean> getChildBeans();
    List<Group> getGroups();
}

public interface ChildBean {
    // ChildType is an enum
    ChildType getChildType();
}

编辑

ParentBean 编辑器

public class ParentBeanEditor extends Composite implements ValueAwareEditor<ParentBean> {

    interface ParentBeanEditorUiBinder extends UiBinder<Widget, ParentBeanEditor> {
    }

    private static ParentBeanEditorUiBinder BINDER = GWT.create(ParentBeanEditorUiBinder.class);

    @Path("groups")
    @UiField
    GroupListEditor groupsEditor;

    public ParentBeanEditor() {
        initWidget(BINDER.createAndBindUi(this));
    }

    @Override
    public void setDelegate(EditorDelegate<ParentBean> delegate) {}

    @Override
    public void flush() {}

    @Override
    public void onPropertyChange(String... paths) {}

    @Override
    public void setValue(ParentBean value) {

        groupsEditor.asEditor().setValue(value.getGroups());
    }
}

组列表编辑器

public class GroupListEditor extends Composite implements IsEditor<ListEditor<Group, GroupEditor>>{

    interface GroupListEditorUiBinder extends UiBinder<VerticalLayoutContainer, TemplateGroupListEditor> {
    }

    private static GroupListEditorUiBinder BINDER = GWT.create(GroupListEditorUiBinder.class);

    private class GroupEditorSource extends EditorSource<GroupEditor> {

        private final GroupListEditor GroupListEditor;

        public GroupEditorSource(GroupListEditor GroupListEditor) {
            this.GroupListEditor = GroupListEditor;
        }

        @Override
        public GroupEditor create(int index) {
            GroupEditor subEditor = new GroupEditor();
            GroupListEditor.getGroupsContainer().insert(subEditor, index);
            return subEditor;
        }

        @Override
        public void dispose(GroupEditor subEditor){
            subEditor.removeFromParent();
        }

        @Override
        public void setIndex(GroupEditor editor, int index){
            GroupListEditor.getGroupsContainer().insert(editor, index);
        }

    }

    private final ListEditor<Group, GroupEditor> editor = ListEditor.of(new GroupEditorSource(this));

    @UiField
    VerticalLayoutContainer groupsContainer;

    public GroupListEditor() {
       initWidget(BINDER.createAndBindUi(this));
    }

    public InsertResizeContainer getGroupsContainer() {
        return groupsContainer;
    }

    @Override
    public ListEditor<Group, GroupEditor> asEditor() {
        return editor;
    }
}

组编辑

public class GroupEditor extends Composite implements ValueAwareEditor<Group> {

    interface GroupEditorUiBinder extends UiBinder<Widget, GroupEditor> {}

    private static GroupEditorUiBinder BINDER = GWT.create(GroupEditorUiBinder.class);

    @Ignore
    @UiField
    FieldSet groupField;

    @UiField
    @Path("childBeans")
    ChildBeanListEditor childBeansEditor;

    @UiField
    @Path("groups")
    GroupListEditor groupsEditor;

    public GroupEditor() {
        initWidget(BINDER.createAndBindUi(this));
    }

    @Override
    public void setDelegate(EditorDelegate<Group> delegate) {}

    @Override
    public void flush() { }

    @Override
    public void onPropertyChange(String... paths) {}

    @Override
    public void setValue(Group value) {
        // When the value is set, update the FieldSet header text
        groupField.setHeadingText(value.getLabel());
        groupsEditor.asEditor().setValue(value.getGroups());
        childBeansEditor.asEditor().setValue(value.getChildBeans());
    }
}

将使用这里ChildBeanListEditor提到的多态编辑器方法。这意味着特定的叶子编辑器根据枚举的值附加到编辑器链。但是,我没有显示该代码,因为我无法正确初始化。ChildBean.getType()GroupListEditor

4

1 回答 1

0

关于您的代码的两个问题:

为什么ParentBeanEditor.setValue要向它的孩子提供数据?由此看来,这是一种解决GroupListEditor未获取数据这一事实的方法。这应该不是必需的,并且可能通过在时间之前连接子编辑器而导致您的 NPE。

然后,假设这一点,似乎遵循的GroupListEditor是没有获取数据链。缺少这些表明编辑器框架没有意识到这一点。所有基本接线看起来都是正确的,除了一件事:您的 EditorDriver 在哪里?

如果您尝试通过调用来使用编辑器框架parentBeanEditor.setValue并且没有驱动程序,那么您将错过该工具的大部分关键功能。您应该能够要求驱动程序为您完成这项工作,而不是在整个树中调用您自己的 setValue 方法。

快速测试 - 尝试以不应该编译的方式破坏某些东西。这将包括将@Path注释更改为类似的内容@Path("doesnt.exist"),并尝试运行应用程序。你应该得到一个重新绑定错误,因为没有这样的路径。如果你不明白这一点,你肯定需要创建和使用驱动程序。

首先,尝试驱动程序本身:

从您的代码中不太清楚您使用的是哪种模型,所以我假设SimpleBeanEditorDriver对您来说就足够了 - 另一个主要选项是,但即使您使用RequestFactoryEditorDriver它实际上也没有必要使用RequestFactoryEditorDriver请求工厂。

Driver 在两件事上是通用的:您打算编辑的 bean 类型和负责它的编辑器类型。它使用这些通用参数来遍历这两个对象并生成绑定数据所需的代码。你的可能看起来像这样:

public interface Driver extends 
        SimpleBeanEditorDriver<ParentBean, ParentBeanEditor> { }

我们声明这些就像UiBinder接口一样 - 足够的细节让代码生成器环顾四周并连接必需品。现在我们有了类型,我们创建一个实例。这可能在您的视图中创建,但仍可能由某些演示者逻辑拥有和控制。请注意,这不像uibinder - 我们不能保留静态实例,因为每个实例都直接连接到特定的编辑器实例。

这里有两个步骤 - 创建驱动程序,并将其初始化为给定的编辑器实例(以及所有子编辑器,这将是自动的):

ParentBeanEditor editor = ...;
Driver driver = GWT.create(Driver.class);
driver.initialize(editor);

接下来我们通过将数据传递给驱动程序来绑定数据——它负责将子对象传递给每个子编辑器的 setValue 方法,并连接 ListEditor 所需的编辑器链。

driver.edit(parentInstance);

现在用户可以查看或编辑对象,因为您的应用程序要求有效。编辑完成后(假设他们点击了 Save 按钮),我们可以将编辑器中的所有更改刷新回实例(请注意,我们仍在使用相同的驱动程序实例,仍然持有该特定的编辑器实例):

ParentBean instance = driver.flush();

请注意,我们也可以只是调用driver.flush()并重用之前的引用parentInstance- 它是同一件事。

假设到目前为止这一切都有意义,可以进行一些清理 - ParentBeanEditor 并没有真正使用 ValueAwareEditor 方法,因此可以将它们删除:

public class ParentBeanEditor extends Composite implements Editor<ParentBean> {

    interface ParentBeanEditorUiBinder extends UiBinder<Widget, ParentBeanEditor> {
    }

    private static ParentBeanEditorUiBinder BINDER = GWT.create(ParentBeanEditorUiBinder.class);

    @Path("groups")
    @UiField
    GroupListEditor groupsEditor;

    public ParentBeanEditor() {
        initWidget(BINDER.createAndBindUi(this));
    }
}

观察我们仍然实现Editor<ParentBean>- 这允许驱动泛型有意义,并声明我们有可能本身是子编辑器的字段要连接。另外:事实证明,这里的注释是不必要的 - 与属性 ( / ==> ) 或属性名称加“编辑器” ( )@Path具有相同名称的任何字段/方法。如果编辑器包含的字段是编辑器,但未映射到 bean 中的属性,您将收到错误消息。如果您确实是故意这样做的(例如,用于搜索的文本框,而不是用于数据输入的文本框),您可以使用.getGroups()setGroups()groupsgroupsEditor@Ignore

于 2012-12-06T23:52:21.120 回答