2012-05-02 2 views
2

У меня есть простой EMF модель следующего вида:Databinding в контейнер неизвестного типа

EClass FooGroup { 
    EString name; 
    @Properties(containment=true, upper=-1) 
    List<Node> nodes; 
} 
EClass BarGroup { 
    EString name; 
    @Properties(containment=true, upper=-1) 
    List<Node> nodes; 
} 
EClass Node { 
    EString name; 
} 

Я хочу, чтобы показать все имена узлов в простом TableViewer вместе с именем их родительской группы. К сожалению, eContainer() - это операция, а не функция. Это означает, что я не могу использовать структуру привязки JFace для привязки этого свойства к графическому интерфейсу.

Как я могу решить эту проблему? Я создаю производную функцию? Есть ли какие-нибудь трюки?

+1

Есть ли причина, по которой вы не указываете Узел ссылку на ее родительскую группу? –

+0

Приведенный выше пример упрощен. Существует несколько атрибутов группы, в которых может содержаться узел, поэтому нет единого EOpposite отношения. – parasietje

ответ

3

Я не могу придумать способ использования eContainer в привязке данных EMF, но было бы не так сложно добавить назначенную родительскую ссылку на узел и обновить ее программно всякий раз, когда eContainer изменится.

Другим решением является добавление родителя, а затем изменить сгенерированный код:

/* 
* @generated NOT 
*/ 
public Group getParent() { 
    if (eContainer() instanceof Group) { 
     return (Group) eContainer(); 
    } 
    return null; 
} 

Тогда вы могли бы использовать FeaturePath, чтобы получить EMFProperty так:

IEMFProperty groupNameProperty = EMFProperties.value(
     FeaturePath.fromList(
     ModelPackage.Literals.NODE__PARENT, 
     ModelPackage.Literals.GROUP__NAME 
    ) 
    ); 
+1

Я добавил производный атрибут «parent», который автоматически обновляется путем регистрации адаптера в конструкторе объекта. – parasietje

0

Там является стандартным способом для этого:

Создайте ссылку в дочернем объекте на родительский объект с соответствующими opposite и container.

Таким образом, связь между классами очевидна в модели, и она поддерживается автоматически, поэтому вам не нужно писать какой-либо пользовательский код.

Ниже приведен пример этого в Xcore:

class Master { 
    contains Slave[] slaves opposite master 
} 

class Slave { 
    container Master master opposite slaves 
} 

А почему бы не то же самое в Ecore также, в то время как мы здесь:

<eClassifiers xsi:type="ecore:EClass" name="Master"> 
    <eStructuralFeatures xsi:type="ecore:EReference" name="slaves" eType="#//Slave" 
     containment="true" eOpposite="#//Slave/master"/> 
</eClassifiers> 
<eClassifiers xsi:type="ecore:EClass" name="Slave"> 
    <eStructuralFeatures xsi:type="ecore:EReference" name="master" eType="#//Master" 
     eOpposite="#//Master/slaves"/> 
</eClassifiers> 
+0

Это действительно работает в приведенном выше примере. Я изменил вопрос, чтобы более четко показать проблему: если узел может содержаться в разных типах объектов, вы не можете определить одну противоположную ссылку. – parasietje

+0

@parasietje: Ах, я вижу. Но это хорошо, чтобы эта техника была размещена на этом сайте; Я не знал об этом до недавнего времени. – Lii

1

Если вы никогда не должны переместите узлы из одного из контейнеров в другой, и вы никогда не смешиваете узлы из разных вместе, тогда вы можете использовать следующее решение.

Идея заключается в создании подклассов для узла, по одному для каждого места, в котором они хранятся. Затем подклассы могут иметь нормальную ссылку на контейнер.

EDIT: Решив ваш вопрос более внимательно, я вижу, что вы должны уметь обрабатывать объекты равномерно, и в этом случае это не сработает. Но, может быть, мой third solution будет!

В любом случае я оставлю этот ответ. Может быть, это будет полезно для других людей.

class FooGroup { 
    String name 
    contains FooNode[] nodes opposite group 
} 

class BarGroup { 
    String name 
    contains BarNode[] nodes opposite group 
} 

class Node { 
    String name 
} 

class BarNode extends Node { 
    container BarGroup group opposite nodes 
} 

class FooNode extends Node { 
    container FooGroup group opposite nodes 
} 
0

Возможно создание пользовательского класса контейнерных свойств, который решает это.

Таким образом, вам не нужно изменять классы моделей, чтобы они могли привязываться к контейнеру. Новое свойство будет полезно для всех электронных объектов.

public static IValueProperty containerProperty() { 
    return new ContainerProperty(); 
} 

public class ContainerProperty extends ValueProperty { 
    @Override 
    public IObservableValue observe(Realm realm, Object source) { 
     return Observables.constantObservableValue(realm, 
      source == null ? null : ((EObject) source).eContainer(), 
      getValueType()); 
    } 

    @Override 
    protected Object doGetValue(Object source) { 
     return ((EObject) source).eContainer(); 
    } 

    @Override 
    public Object getValueType() { 
     return EObject.class; 
    } 
}; 

Пример использования:

IObservableValue obs = containerProperty().observeDetail(node); 

Этот класс не прислушивается к изменениям контейнера. Но я думаю, что можно было бы реализовать такое свойство. Возможно, для этого подходит класс SimpleValueProperty.