GXT之旅:第七章:MVC——MVC重构项目(2)

使用MVC重构RSSReader项目——Navigation区域

上一节,在程序的入口文件(RSSReader),我们派发了EventType为Init的AppEvent,AppController会处理此事件,将其转发到AppView。依次的,AppView会的处理该事件,去调用onInit方法,完成基础的UI创建。在此过程中负责了程序主体的区域创建。但是,唯一没有处理的,就是没有把组装好的components添加到UI。

那么现在,我们需要再分别创建几组Controller和View,分别去负责RSSReader项目其他的各个区域。首先我们要创建一对Controller-View,去处理Navigation区域。

大致思路如下:

  • 负责navigation区域的controller,能够将Init EventType转发到对应的View里
  • 负责navigation区域的view,会处理Init EventType,在处理的过程中,又会派发一个新的事件(NavPanelReady)——此事件会承载着NavPanel的实例被派发到Dispatcher中。
  • AppController会监听此事件(NavPanelReady),当接收到此事件传入的时候,会将其转发到AppView。
  • AppView会处理会理NavPanelReady的事件——将其传递的NavPanel实例,加入到ViewPort上

此前,onModuleLoad方法里已经派发了UIReady事件。因此,NavPanel应该已经被添加到Viewport里,显示出来。具体实现步骤如下:

  • 在com.danielvaughan.rssreader.client.mvc.events.AppEvents类,加入新的EventType——NavPanelReady

public static final EventType NavPanelReady = new EventType();

  • 新建NavController extends Controller

package com.danielvaughan.rssreader.client.mvc.controllers;

import com.extjs.gxt.ui.client.mvc.AppEvent;
import com.extjs.gxt.ui.client.mvc.Controller;

public class NavController extends Controller {

	@Override
	public void handleEvent(AppEvent event) {
		
		
	}

}


  • 新建NavView extends View

package com.danielvaughan.rssreader.client.mvc.views;

import com.extjs.gxt.ui.client.mvc.AppEvent;
import com.extjs.gxt.ui.client.mvc.Controller;
import com.extjs.gxt.ui.client.mvc.View;

public class NavView extends View {

	public NavView(Controller controller) {
		super(controller);
	}

	@Override
	protected void handleEvent(AppEvent event) {

	}

}

  • 在NavController的构造函数里,注册Init EventType

public NavController() {
registerEventTypes(AppEvents.Init);
}

  • 在NavController,定义NavView类实例,通过其initialize方法实例化NavView——让controller与view关联起来。实现handleEvent方法,将NavController接收的事件转发到NavView里。

package com.danielvaughan.rssreader.client.mvc.controllers;

import com.danielvaughan.rssreader.client.mvc.events.AppEvents;
import com.danielvaughan.rssreader.client.mvc.views.NavView;
import com.extjs.gxt.ui.client.mvc.AppEvent;
import com.extjs.gxt.ui.client.mvc.Controller;

public class NavController extends Controller {

	private NavView navView;

	public NavController() {
		registerEventTypes(AppEvents.Init);
	}

	@Override
	public void handleEvent(AppEvent event) {
                forwardToView(navView, event);
	}

	@Override
	public void initialize() {
		super.initialize();
		navView = new NavView(this);
	}

}

  • 将com.danielvaughan.rssreader.client.components.RssNavigationPanel类,重命名为NavPanel。然后在NavView类里,加入NavPanel的实例属性

package com.danielvaughan.rssreader.client.mvc.views;

import com.danielvaughan.rssreader.client.components.NavPanel;
import com.extjs.gxt.ui.client.mvc.AppEvent;
import com.extjs.gxt.ui.client.mvc.Controller;
import com.extjs.gxt.ui.client.mvc.View;

public class NavView extends View {

	private final NavPanel navPanel = new NavPanel();

	public NavView(Controller controller) {
		super(controller);
	}

	@Override
	protected void handleEvent(AppEvent event) {

	}

}

  • 在NavView类里实现handleEvent方法——当Init EventType接收到之后,再派发一个新事件(此过程我习惯称之事件联动):NavPanelReady ,并且派发的同时,承载navPanel对象

package com.danielvaughan.rssreader.client.mvc.views;

import com.danielvaughan.rssreader.client.components.NavPanel;
import com.danielvaughan.rssreader.client.mvc.events.AppEvents;
import com.extjs.gxt.ui.client.event.EventType;
import com.extjs.gxt.ui.client.mvc.AppEvent;
import com.extjs.gxt.ui.client.mvc.Controller;
import com.extjs.gxt.ui.client.mvc.Dispatcher;
import com.extjs.gxt.ui.client.mvc.View;

public class NavView extends View {

	private final NavPanel navPanel = new NavPanel();

	public NavView(Controller controller) {
		super(controller);
	}

	@Override
	protected void handleEvent(AppEvent event) {
		EventType eventType = event.getType();

		if (eventType.equals(AppEvents.Init)) {
			Dispatcher.forwardEvent(new AppEvent(AppEvents.NavPanelReady,
					navPanel));
		}
	}

}

  • 既然NavView会派发NavPanelReady事件,我们希望交给AppController注册,也就意味着,AppView会接收到此事件,做后续的操作。

	public AppController() {
		registerEventTypes(AppEvents.Init);
		registerEventTypes(AppEvents.Error);
		registerEventTypes(AppEvents.UIReady);
		registerEventTypes(AppEvents.NavPanelReady);
	}

  • 在AppView对NavPanelReady事件的处理实现如下——将NavPanelReady事件传递的navPanel对象,对后续处理,将其添加到viewport上

package com.danielvaughan.rssreader.client.mvc.views;

import com.danielvaughan.rssreader.client.mvc.events.AppEvents;
import com.extjs.gxt.ui.client.Style.LayoutRegion;
import com.extjs.gxt.ui.client.Style.Orientation;
import com.extjs.gxt.ui.client.event.EventType;
import com.extjs.gxt.ui.client.mvc.AppEvent;
import com.extjs.gxt.ui.client.mvc.Controller;
import com.extjs.gxt.ui.client.mvc.View;
import com.extjs.gxt.ui.client.widget.Component;
import com.extjs.gxt.ui.client.widget.ContentPanel;
import com.extjs.gxt.ui.client.widget.Viewport;
import com.extjs.gxt.ui.client.widget.layout.BorderLayout;
import com.extjs.gxt.ui.client.widget.layout.BorderLayoutData;
import com.extjs.gxt.ui.client.widget.layout.RowLayout;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.RootPanel;

public class AppView extends View {
	private final ContentPanel mainPanel = new ContentPanel();
	private final Viewport viewport = new Viewport();

	public AppView(Controller controller) {
		super(controller);

	}

	@Override
	protected void handleEvent(AppEvent event) {
		EventType eventType = event.getType();
		if (eventType.equals(AppEvents.Init)) {
			onInit(event);
		} else if (eventType.equals(AppEvents.Error)) {
			onError(event);
		} else if (eventType.equals(AppEvents.UIReady)) {
			onUIReady(event);
		}else if (eventType.equals(AppEvents.NavPanelReady)) {
			onNavPanelReady(event);
		}
	}

	private void onInit(AppEvent event) {
		final BorderLayout borderLayout = new BorderLayout();
		viewport.setLayout(borderLayout);
		HTML headerHtml = new HTML();
		headerHtml.setHTML("<h1>RSS Reader</h1>");
		BorderLayoutData northData = new BorderLayoutData(LayoutRegion.NORTH,
				20);
		northData.setCollapsible(false);
		northData.setSplit(false);
		viewport.add(headerHtml, northData);
		BorderLayoutData centerData = new BorderLayoutData(LayoutRegion.CENTER);
		centerData.setCollapsible(false);
		RowLayout rowLayout = new RowLayout(Orientation.VERTICAL);
		mainPanel.setHeaderVisible(false);
		mainPanel.setLayout(rowLayout);
		viewport.add(mainPanel, centerData);
	}

	private void onUIReady(AppEvent event) {
		RootPanel.get().add(viewport);
	}

	private void onNavPanelReady(AppEvent event) {
		BorderLayoutData westData = new BorderLayoutData(LayoutRegion.WEST,
				200, 150, 300);
		westData.setCollapsible(true);
		westData.setSplit(true);
		Component component = event.getData();
		viewport.add(component, westData);
	}

	private void onError(AppEvent event) {
	}
}

  • 所有的准备工作做好了,那么一切事件的触发点,我们要回到RSSReader的onModuleLoad方法里。加入NavController

    @Override
    public void onModuleLoad() {
        final FeedServiceAsync feedService = GWT.create(FeedService.class);
        Registry.register(RSSReaderConstants.FEED_SERVICE, feedService);
        Dispatcher dispatcher = Dispatcher.get();

        dispatcher.addController(new AppController());
        dispatcher.addController(new NavController());

        // 注意:dispatcher.dispatch(AppEvents.Init);会派发Init事件,虽然只是执行了一次派发操作,但是会派发到多个controller中去!
        // 原因:因为AppController和NavController都注册了Init !
        // 顺序:两个controller的接收到event的顺序是根据上面的两行代码(controller的加入顺序)有关!
        dispatcher.dispatch(AppEvents.Init);
        dispatcher.dispatch(AppEvents.UIReady);
    }

  • 程序运行效果如下:

GXT之旅:第七章:MVC——MVC重构项目(2)_第1张图片

你可能感兴趣的:(GXT之旅:第七章:MVC——MVC重构项目(2))