有没有一种方法可以将ObservableList绑定到ObservableMap?

6
我得到的数据格式是一个ObservableMap<T, Foo>。 为了在视图中实现这些数据,我需要将该映射的值以ObservableList<Foo>的格式呈现。
因为我需要使用Map集合中的数据(避免重复和其他原因),所以我想知道是否可以绑定这2个集合。
类似于下面的代码:
ObservableMap<Integer, Foo> data = FXCollections.observableHashMap();
ObservableList<Foo> target = FXCollections.observableArrayList();

// Won't work 
Bindings.bindContent(target, data.values());

数据会在运行时发生变化,因此需要绑定。

编辑: 使用映射值初始化列表无法正常工作,因为将有其他Foo添加到映射中: 例如,使用字符串作为映射值的示例:

ObservableMap<Integer, String> map = FXCollections.observableHashMap();
map.put(1, "a");
map.put(2, "b");

ObservableList<String> list = FXCollections.observableArrayList(map.value());

//map = {1=a, 2=b}
//list = [a, b]
// ok

map.put(3, "c");

//map = {1=a, 2=b, 3=c}
//list = [a, b]
// no update    

你尝试过使用流吗?就像Alexis C.在这篇帖子https://dev59.com/N2855IYBdhLWcg3wy3sc中所描述的那样。 - Constantin Beer
2
https://github.com/TomasMikula/EasyBind - SURU
@SURU 我似乎找不到EasyBinding中将map与list绑定的合适方法,只有list与list之间的绑定。 - Thomas Bernhard
1
在最简单的情况下(仅地图更改,列表为只读),您可以手动侦听地图中的更改并替换列表中的项目。 - kleopatra
是的,我会尝试那种方法。 - Thomas Bernhard
显示剩余3条评论
2个回答

1

从ObservableMap到ObservableList

ObservableMap<Integer, Foo> data = FXCollections.observableHashMap();
ObservableList<Foo> target = FXCollections.observableArrayList(data.values());

2
我想保持目标更新。一旦使用data.values()初始化,将不会识别数据中的更改。 - Thomas Bernhard
1
不,因为observableArrayList(Collection)的API文档明确说明“创建一个新的可观察数组列表,并将集合col的内容添加到其中”。 - kleopatra
@kleopatra,是的,但他想要绑定它们,并在将新值添加到映射后自动将其放入列表中,而不需要再进行额外的更新,因此您的解决方案行不通。 - SURU
@SURU a) 从未(可能以后会)发布过_solution_。如果您指的是我的评论/ s:b)手动侦听器始终有效c)我在建议自定义transformList时是错误的(需要支持源是列表)-由ObservableMap支持的自定义ObservableList将会做到。 - kleopatra

1

我在Java中没有找到内置的解决方案。当Map是数据源时,我使用简单的MapChangeListener,而List仅用于跟踪Map值列表的更改。

    ObservableMap<String, String> map = FXCollections.observableHashMap();
    ObservableList<String> list = FXCollections.observableArrayList();

    MapChangeListener<String, String> listener = c -> {
        if (c.wasRemoved()) {
            list.remove(c.getValueRemoved());
        }

        if (c.wasAdded()) {
            list.add(c.getValueAdded());
        }
    };

    map.addListener(listener);

    map.put("1", "A");
    map.put("2", "B");
    map.put("1", "A'");

    assertThat(list).containsExactlyInAnyOrder("A'", "B");

你应该将可观察列表保持为私有,并且只在外部暴露一个不可修改的可观察列表,以防止意外添加不在映射中的列表条目。

我为此创建了一个实用类。这样可以轻松地重复使用代码。您可以在这里找到Gist。 - Aron Hoogeveen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接