【问题标题】:How must one use a ListEditor as a child of another Editor?必须如何将 ListEditor 用作另一个编辑器的子项?
【发布时间】:2012-12-06 16:54:47
【问题描述】:

我正在使用 GWT 2.5.0

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

这是我如何尝试这样做的解释。

从下面的代码中,我创建了一个ParentBeanEditor,它由另一个编辑器GroupListEditor 组成。
GroupListEditor 实现 IsEditor<ListEditor<Group, GroupEditor>>
然后,GroupEditor 包含一个GroupListEditor 子编辑器和一个ChildBeanEditor

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

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

示例

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

【问题讨论】:

  • 你能分享你的代码吗?它真的应该像最初看起来一样简单。
  • 完成。它被擦洗了一点,根据我在底部的解释,有些部分被遗漏了。
  • 究竟是什么问题?你期望什么没有发生? (或者没想到发生了什么)让我们也将 ValueAwareEditor 分开,因为它试图解决您实际上没有描述的问题。
  • 组列表编辑器未获取编辑器链。我在ListEditorWrapper 第 95 行得到一个 NPE。我将修改这个问题,使其更具体。过失。
  • 这有点模棱两可 :( 它现在应该说明我想要做什么,我打算如何做,我预期会发生什么,以及没有发生什么。

标签: gwt gxt gwt-editors


【解决方案1】:

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

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

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

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

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

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

从您的代码中不太清楚您使用的是哪种模型,所以我假设SimpleBeanEditorDriver 就足够了 - 另一个主要选项是RequestFactoryEditorDriver,但事实并非如此即使您使用RequestFactory,实际上也需要使用RequestFactoryEditorDriver

驱动程序在两件事上是通用的:您打算编辑的 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);

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

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&lt;ParentBean&gt; - 这使驱动泛型变得有意义,并声明我们有可能本身是子编辑器的字段要连接起来。另外:事实证明,这里的 @Path 注释是不必要的 - 任何与属性同名的字段/方法 (getGroups()/setGroups() ==> groups) 或属性名称加上 'Editor ' (groupsEditor)。如果编辑器包含的字段是编辑器,但未映射到 bean 中的属性,您将收到错误消息。如果您确实是故意这样做的(例如,用于搜索的文本框,而不是用于数据输入的文本框),您可以使用@Ignore 对其进行标记。

【讨论】:

  • 我试图说明我从最高点组合起来的编辑器层次结构。我(有点)故意省略了编辑器驱动程序的部分,因为我认为它从Editors Dev Guide 开始有点明显/直截了当。你写的其他所有东西都很有意义。我从实现 Editor 开始,但正如您所观察到的,尝试使用 ValueAwareEditor 来尝试强制执行。显然,我必须回去澄清我的假设。 :)
  • 对不起 - 只能放弃我所拥有的。也就是说 - 考虑制作一个只使用小块的本地驱动程序以确保它工作 - 你可能有一个 private@Ignore 在某个地方阻止驱动程序的东西走完整的树。
  • 我做了一个奇怪的假设 :) 使用你描述的驱动程序是可行的。但是我有一个扩展Editor 的接口,而ParentBeanEditor 扩展了该接口。然后我将驱动程序设置为使用接口而不是 ParentBeanEditor,但使用 ParentBeanEditor 进行初始化。我只是假设,由于我的 ParentBeanEditor 实现了该接口,驱动程序不会有问题。这就是为什么它对我不起作用。这有意义吗?
  • 是的 - 这不起作用,因为当驱动程序检查 Editor 类型(即'Editor')时,它没有找到子编辑器,所以它什么也不做。这使得一些任务变得棘手,比如从视图中分离出驱动程序——我发现最好的解决方案是让视图暴露一个SimpleBeanEditorDriver&lt;T, ?&gt;,这样演示者就可以在不创建它的情况下对其进行操作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-25
  • 1970-01-01
  • 2020-12-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多