Статьи

Получить на вашей ViewModel

В течение некоторого времени я тихо взламывал инструмент отчетности Eclipse Business Expense Tool (EBERT) из проекта «Примеры». Моя цель — превратить это приложение в яркий пример того, как можно создать реальное (хотя и относительно простое) приложение на основе Eclipse RCP , eRCP и RAP .

Мне было неловко, чтобы разобраться в координации взглядов. Приложение состоит из трех видов. В версиях RCP и RAP представления составляются, как показано ниже, с BinderView слева, ExpenseReportView вверху справа и LineItemView внизу справа. В версии eRCP, представления сгруппированы и выборочно представлены.

Сначала я использовал сервис выбора для координации видов. Например, ListViewer в BinderView настроен как поставщик выбора, а ExpenseReportView настроен как потребитель выбора: когда ExpenseReportвыбран, ExpenseReportView обновляется сам. Хорошая особенность этого механизма заключается в том, что он позволяет полностью отделить представления друг от друга, а также позволяет другим представлениям выступать в качестве поставщиков выбора. Еще одна очень приятная особенность использования службы выбора для этого заключается в том, что она хорошо работает в многопользовательской среде RAP, поскольку каждый пользователь получает свою собственную копию рабочей среды (и, соответственно, свою собственную копию службы выбора). С другой стороны, управление такими вещами, как, например, случай, когда, например, выбранный ExpenseReport удаляется, требует некоторой работы (когда ExpenseReport удаляется из BinderView, следует ожидать, что ExpenseReportView и LineItemView станут пустыми). Это не особенно трудно справиться с этим, но кажется немного грязным. Это,и служба выбора на самом деле не реализована в eRCP (потому что она действительно бесполезна в этой среде).

Я решил вместо этого ввести класс ViewModel . ViewModel предоставляет, как следует из названия, модель моего представления. Для этого приложения модель представления довольно проста: она отслеживает «текущие» ExpensesBinder , ExpenseReport и LineItem . Различные виды все говорят модели представления о действиях пользователя. Модель представления обновляется в ответ на эти действия и уведомляет различные представления об изменении.

Когда, например, ExpenseReport выбран в BinderView, модель представления информируется об изменении:

// TODO Consider using addPostSelectionChangedListener instead
expenseReportViewer.addSelectionChangedListener(new ISelectionChangedListener() {
	public void selectionChanged(SelectionChangedEvent event) {
		IStructuredSelection selection = (IStructuredSelection)event.getSelection();
		getViewModel().setReport((ExpenseReport) selection.getFirstElement());
	}
});

Модель представления отвечает, устанавливая «текущий» ExpenseReport, установленный на недавно выбранный, и «текущий» LineItem должен быть нулевым. Затем все слушатели информируются об изменении. Код представляет собой довольно простую реализацию шаблона наблюдателя :

public void setReport(ExpenseReport report) {
	this.report = report;
	this.lineItem = null;

	Object[] listeners = listenerList.getListeners();
	for(int index=0;index<listeners.length;index++) {
		IViewModelListener listener = (IViewModelListener) listeners[index];
		listener.reportChanged(this.report);
		listener.lineItemChanged(this.lineItem);
	}
}

Каждое из представлений слушает модель представления. Когда наблюдатель уведомляет их об изменении, они реагируют соответствующим образом. Например, LineItemView отвечает на метод lineItemChanged (LineItem), обновляя себя, чтобы отразить изменение:

IViewModelListener viewModelListener = new IViewModelListener() {
	public void binderChanged(ExpensesBinder binder) {
	}

	public void lineItemChanged(final LineItem item) {
		syncExec(new Runnable() {
			public void run() {
				setLineItem(item);
			};
		});
	}
	public void reportChanged(ExpenseReport report) {}
};

Другие типы и представления обрабатываются аналогичным образом.

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

Я поговорю об этом в следующий раз …

Пожалуйста, сделайте это, если есть что-то, что можно сделать лучше.

С http://dev.eclipse.org/blogs/wayne