源于《EMF.Edit Framework Programmgering's Guide》
EMF.Edit里面有幾個類比較繞,很容易被搞得暈頭轉向,所以需要澄清以下:
★AdapterFactoryContentProvider, ItemProviderAdapterFactory和ItemProviderAdapter之間的關系,ItemProviderAdapterFactory用來創建各種Adapter以及將各種notifier跟這些adapter關聯起來,AdapterFactoryContentProvider包裝了一個ItemProviderAdapterFactory(AdapterFactory),它用來將JFace需要的content provider代理到item content provider上,對content provider各種方法的調用將調用到相應的item content provider上,對org.eclipse.jface.viewers.IStructuredContentProvider的調用將代理到IStructuredItemContentProvider上,對ITreeContentProvider的調用將代理到ITreeItemContentProvider上,而對IPropertySourceProvider的調用將代理到IItemPropertySource,而ItemProviderAdapter是所有ItemProvider的基類,AdapterFactoryLabelProvider和ItemProviderAdapter之間也存在類似的關系
★為了顯示model內容,我們需要使用content provider和label provider,而編輯model內容則需要使用到editing domain,AdapterFactoryEditingDomain是一個和AdapterFactoryContentProvider、AdapterFactoryLabelProvider類似的東東
★editing domain主要有兩個功能:一個是作為command的factory(所以它的實現類是AdapterFactoryEditingDomain);另一個對EMF Model(ResourceSet,因此提供了getResource()方法)進行管理
★EditingDomain,AdapterFactoryEditingDomain,EditingDomainItemProvider和Command之間的關系,AdapterFactoryEditingDomain實現了EditingDomain接口,AdapterFactoryEditingDomain和AdapterFactoryContentProvider一樣,也是用來將EditingDomain的方法代理到EditingDomainItemProvider上去。
從一般的操作說起,比如從一個company對象上刪除一個department對象,通常我們的做法是:
但是如果是使用command,則會這樣做:
不過這個做法有一個問題,就是不是很通用,因為所有的刪除操作基本上都差不多,所以還需要繼續抽象,這時就必須引入EditingDomain.
EditingDomain的接口定義如下:
為了創建一個Command對象,我們需要構造一個CommandParameter對象。在createCommand方法里面會調用指定的Command的靜態create方法來創建指定的Command對象,通過使用create方法,我們可以對上面的操作做進一步的改寫:
通過上面的改寫,差不多實現了一個通用的刪除操作流程
接下來我們可以看看一個command的創建過程,首先是調用指定command的靜態create方法,該方法將調用EditingDomain的createCommand方法,AdapterFactoryEditingDomain作為EditingDomain的實現類,又將command的創建過程代理到EditingDomainItemProvider上,在Itemprovider(實現了EditingDomainItemProvider接口)中,最終使用new創建指定的Command實例
我們可以采用多種方式對command定制,第一種就是復寫generated的EditingDomainItemProvider實現類的createCommand方法:
這里的RemoveDepartmentCommand 就是我們自己實現的刪除操作。
第二種方式就是復寫createRemoveCommand()來實現定制:
通知的處理
在創建AdapterFactoryContentProvider的時候會將其作為一個listener注冊到AdapterFactory里面,這個AdapterFactory實現了IChangeNotifier接口,而AdapterFactory在創建每一個ItemProvider的時候又會把自己傳遞過去,從而使得AdapterFactory成為model的消息分發中心,在AdapterFactoryContentProvider又會記錄所有需要接受通知的viewer(也就是為其提供了content provider的viewer)。
當model被改變之后,將觸發和該model相關的adapter的notifyChanged()方法(這里面的adapter就包括itemprovider),當然這里還有一個過濾的過程,只把那些跟viewer相關的notification才會發送給viewer。為了將notification繼續傳遞,會使用ViewerNotification這樣一個對象來對notifation以及其他的信息進行封裝,因此它繼承了Notification,除了Notification相關的信息之外,還封裝了要更新的viewer的相關元素,IViewerNotification 的定義如下:
對于消息的傳遞還會進行分類,這個是在notifyChanged這個方法里面做的,如下面的代碼:
可以看出,如果是attribute,那么會對label進行更新,如果是reference,那么需要更新content了,否則什么都不做。fireNotifyChanged方法是在ItemProviderAdapter(就是所有ItemProvider的基類)里面定義的,它會把notifaction傳給adapter factory,前面我們說過adapter factory是notification的分發器,因此它會將notification發送給所有注冊的listener,我們前面也說過AdapterFactory實現IChangeNotifier接口,并作為listener注冊到adapter factory中去了,因此在最后會調用adapter factory的fireNotifyChanged方法,當然了adapter factory也會將notification代理別的對象(可能是tree或者table的content/label provider,當然在emf中就是itemprovider了)上去,最后viewer被更新了。
EMF.Edit里面有幾個類比較繞,很容易被搞得暈頭轉向,所以需要澄清以下:
★AdapterFactoryContentProvider, ItemProviderAdapterFactory和ItemProviderAdapter之間的關系,ItemProviderAdapterFactory用來創建各種Adapter以及將各種notifier跟這些adapter關聯起來,AdapterFactoryContentProvider包裝了一個ItemProviderAdapterFactory(AdapterFactory),它用來將JFace需要的content provider代理到item content provider上,對content provider各種方法的調用將調用到相應的item content provider上,對org.eclipse.jface.viewers.IStructuredContentProvider的調用將代理到IStructuredItemContentProvider上,對ITreeContentProvider的調用將代理到ITreeItemContentProvider上,而對IPropertySourceProvider的調用將代理到IItemPropertySource,而ItemProviderAdapter是所有ItemProvider的基類,AdapterFactoryLabelProvider和ItemProviderAdapter之間也存在類似的關系
★為了顯示model內容,我們需要使用content provider和label provider,而編輯model內容則需要使用到editing domain,AdapterFactoryEditingDomain是一個和AdapterFactoryContentProvider、AdapterFactoryLabelProvider類似的東東
★editing domain主要有兩個功能:一個是作為command的factory(所以它的實現類是AdapterFactoryEditingDomain);另一個對EMF Model(ResourceSet,因此提供了getResource()方法)進行管理
★EditingDomain,AdapterFactoryEditingDomain,EditingDomainItemProvider和Command之間的關系,AdapterFactoryEditingDomain實現了EditingDomain接口,AdapterFactoryEditingDomain和AdapterFactoryContentProvider一樣,也是用來將EditingDomain的方法代理到EditingDomainItemProvider上去。
從一般的操作說起,比如從一個company對象上刪除一個department對象,通常我們的做法是:
java 代碼
- Department d = ...
- Company c = ...
- c.getDepartments().remove(d);
但是如果是使用command,則會這樣做:
java 代碼
- Department d = ...
- Company c = ...
- EditingDomain ed = ...
- RemoveCommand cmd =
- new RemoveCommand(ed, c, CompanyPackage.eINSTANCE.getCompany_Departments(), d);
- ed.getCommandStack().execute(cmd);
不過這個做法有一個問題,就是不是很通用,因為所有的刪除操作基本上都差不多,所以還需要繼續抽象,這時就必須引入EditingDomain.
EditingDomain的接口定義如下:
java 代碼
- public interface EditingDomain
- {
- ...
- Command createCommand(Class commandClass, CommandParameter commandParameter);
- ...
- }
為了創建一個Command對象,我們需要構造一個CommandParameter對象。在createCommand方法里面會調用指定的Command的靜態create方法來創建指定的Command對象,通過使用create方法,我們可以對上面的操作做進一步的改寫:
java 代碼
- Department d = ...
- EditingDomain ed = ...
- Command cmd = RemoveCommand.create(ed, d);
- ed.getCommandStack().execute(cmd);
通過上面的改寫,差不多實現了一個通用的刪除操作流程
接下來我們可以看看一個command的創建過程,首先是調用指定command的靜態create方法,該方法將調用EditingDomain的createCommand方法,AdapterFactoryEditingDomain作為EditingDomain的實現類,又將command的創建過程代理到EditingDomainItemProvider上,在Itemprovider(實現了EditingDomainItemProvider接口)中,最終使用new創建指定的Command實例
我們可以采用多種方式對command定制,第一種就是復寫generated的EditingDomainItemProvider實現類的createCommand方法:
java 代碼
- public class CompanyItemProvider ...
- {
- ...
- public Command createCommand(final Object object, ...)
- {
- if (commandClass == RemoveCommand.class)
- {
- return new RemoveDepartmentCommand(...);
- }
- return super.createCommand(...);
- }
- }
這里的RemoveDepartmentCommand 就是我們自己實現的刪除操作。
第二種方式就是復寫createRemoveCommand()來實現定制:
java 代碼
- protected Command createRemoveCommand(...)
- {
- return new RemoveDepartmentCommand(...);
- }
通知的處理
在創建AdapterFactoryContentProvider的時候會將其作為一個listener注冊到AdapterFactory里面,這個AdapterFactory實現了IChangeNotifier接口,而AdapterFactory在創建每一個ItemProvider的時候又會把自己傳遞過去,從而使得AdapterFactory成為model的消息分發中心,在AdapterFactoryContentProvider又會記錄所有需要接受通知的viewer(也就是為其提供了content provider的viewer)。
當model被改變之后,將觸發和該model相關的adapter的notifyChanged()方法(這里面的adapter就包括itemprovider),當然這里還有一個過濾的過程,只把那些跟viewer相關的notification才會發送給viewer。為了將notification繼續傳遞,會使用ViewerNotification這樣一個對象來對notifation以及其他的信息進行封裝,因此它繼承了Notification,除了Notification相關的信息之外,還封裝了要更新的viewer的相關元素,IViewerNotification 的定義如下:
java 代碼
- public interface IViewerNotification extends Notification
- {
- Object getElement();
- boolean isContentRefresh();
- boolean isLabelUpdate();
- }
對于消息的傳遞還會進行分類,這個是在notifyChanged這個方法里面做的,如下面的代碼:
java 代碼
- public void notifyChanged(Notification notification)
- {
- ...
- switch (notification.getFeatureID(Company.class))
- {
- case CompanyPackage.COMPANY__NAME:
- //ViewerNotification(Notification decoratedNotification, Object element,
- boolean contentRefresh, boolean labelUpdate)
- fireNotifyChanged(new ViewerNotification(notification, ..., false, true));
- return;
- case CompanyPackage.COMPANY__DEPARTMENT:
- fireNotifyChanged(new ViewerNotification(notification, ..., true, false));
- return;
- }
- super.notifyChanged(notification);
- }
可以看出,如果是attribute,那么會對label進行更新,如果是reference,那么需要更新content了,否則什么都不做。fireNotifyChanged方法是在ItemProviderAdapter(就是所有ItemProvider的基類)里面定義的,它會把notifaction傳給adapter factory,前面我們說過adapter factory是notification的分發器,因此它會將notification發送給所有注冊的listener,我們前面也說過AdapterFactory實現IChangeNotifier接口,并作為listener注冊到adapter factory中去了,因此在最后會調用adapter factory的fireNotifyChanged方法,當然了adapter factory也會將notification代理別的對象(可能是tree或者table的content/label provider,當然在emf中就是itemprovider了)上去,最后viewer被更新了。
安徽新華電腦學校專業職業規劃師為你提供更多幫助【在線咨詢】