We implemented a binding for some typical Grid usages in application. It works just fine, except if you modify a store, for example add a record, you'd see n + TWO identical records in view. When I examined store's state, it shown n + 1 values.
It goes as if I have a grid with one record shown in it and call: grid.getStore().add(modelFactory.createModel(event.getBean())); I now have:
The second and the third lines are equal and third one can't be selected. Also, it is not present in grid.getStore().
Sources:
freqsGrid = new AwesomeGridPanel() {
    @Override
    public void createColumns() {/**/}
};
freqBinding = AwesomeGridBinding.createGridBinding(freqsGrid, "frequencies");
Simple binding source. It maps model's List property to grid as is.
public class AwesomeGridBinding {
    public static FieldBinding createGridBinding(AwesomeGridPanel grid, String property) {
        return new FieldBinding(new AwesomeGridAdapterField(grid), property);
    }
}
class AwesomeGridAdapterField<T> extends AdapterField {
    protected AwesomeGridPanel grid;
    private StoreListener<BeanModel> storeChangedListener;
    public AwesomeGridAdapterField(AwesomeGridPanel grid) {
        super(grid);
        this.grid = grid;
        configureGrid(grid, this);
    }
    @Override
    public void setValue(Object value) {
        List data;
        if (value == null)
            data = new ArrayList<>();
        else if (!(value instanceof List))
            throw new IllegalArgumentException();
        else
            data = (List) value;
        grid.getStore().setMonitorChanges(false);
        grid.getStore().setFiresEvents(false);
        setResults(grid.getStore(), data);
        grid.getStore().setFiresEvents(true);
        grid.getStore().setMonitorChanges(true);
If I remove the line below, view stops to show n+2 lines after add, and begins to show added line even after formBinding.bind(createModel(bean)); to another bean.
        grid.getGrid().getView().refresh(false);
    }
    @Override
    public Object getValue() {
        List<T> result = new ArrayList<>();
        for (BeanModel bm : grid.getStore().getModels())
            if (isBeanForResult(bm))
                result.add(extractResult(bm));
        return result;
    }
    protected void setResults(ListStore<BeanModel> store, List data) {
        store.removeAll();
        for (Object obj : data)
            if (obj instanceof BeanModel)
                store.add((BeanModel) obj);
            else
                throw new IllegalArgumentException();
    }
    protected boolean isBeanForResult(BeanModel beanModel) {
        return true;
    }
    protected T extractResult(BeanModel bmFromStore) {
        return bmFromStore.getBean();
    }
    private final EventType[] STORE_EVENTS = {Store.Add, Store.Clear, Store.DataChanged, Store.Remove, Store.Update};
    protected void configureGrid(final AwesomeGridPanel grid, final AdapterField field) {
        grid.getStore().setMonitorChanges(true);
//        grid.getStore().removeAllListeners();
        if (storeChangedListener != null)
            grid.getStore().removeStoreListener(storeChangedListener);
        storeChangedListener = new StoreListener<BeanModel>() {
            @Override
            public void handleEvent(StoreEvent<BeanModel> e) {
                super.handleEvent(e);
                for (EventType se : STORE_EVENTS) {
                    if (se != e.getType())
                        continue;
                    field.fireEvent(Events.Change);
                    return;
                }
            }
        };
        grid.getStore().addStoreListener(storeChangedListener);
    }
}
