摘要:Smart Client Software Factory 首先是为 Smart Client 应用设计的编程框架,通过合理的使用架构模式、设计模式和最佳实践建立 Smart Client 的指导原则和框架基础。基于MVP模式(Model-View-Presenter)。,它通过 Visual Studio 的 GuidanceAutomation 扩展了 VS 的功能。

该框架主要用于开发类似与工具类型的软件,支持多视图,自定界面视图,类似于Visual Studio,PowerDesigner,MapWinGis等界面。结合现在所做的项目,主要说一下几种功能:

 

一、SmartClient中的EventBroker(EventPublication与EventSubscription):

某个Event贴上EventPublication的Attribute,则我们就可以在相关的方法上利用EventSubscription这个Attribute就可以轻松订阅相关EventPublication。类似与事件委托,一对多的关系,发布一个事件,多个地方可以接收。

SCSF 启动过程中,ObjectBuilder 会到被创建的对象上去找标有 EventPublicationAttribute 和 EventSubscriptionAttribute 的事件和方法,并通过 topic, 和 PublicationScope 把对应的事件发布和接受者动态的关联起来,放到 WorkItem 的 EventTopic 集合中。

eg.

  

[EventPublication(EventTopicNames.MapGeometrySelectedTopic)]
        public event EventHandler<DataEventArgs<List<SelectObject>>> GeometrySelectedChanged;
 
public class EventTopicNames
{

地图选择对象改变事件名

      

public const string MapGeometrySelectedTopic = "topic://MapView/GeometrySelected";
}
 
        [EventSubscription(EventTopicNames.MapGeometrySelectedTopic)]
        public void OnMapGeometrySelected(object sender, DataEventArgs<List<SelectObject>> e)
        {
            flowLayoutPanel1.Controls.Clear();
            BindSelectedView(e.Data);
            //_pgSelectElem.SelectedObject = null;
        }

 

该例子主要是在地图上框选出区域内的设备,然后在属性窗口中显示这些设备的信息

 

二、RootWorkItem

整个 SCSF 应用有且只有一个 RootWorkItem。

       

public T ShowSingletonView<T>(string viewName) where T : IDockContent
        {
            T frm;
            frm = WorkItem.RootWorkItem.SmartParts.Get<T>(viewName);
            if (frm == null)
                frm = WorkItem.RootWorkItem.SmartParts.AddNew<T>(viewName);
            ShowView(frm);
            return frm;
        }

将窗口注册到RootWorkItem中。

 

三、ModuleController 模块控制逻辑

public class ModuleController : WorkItemController
    {
        public override void Run()
        {
            AddServices();
            ExtendMenu();
            ExtendToolStrip();
            AddViews();
        }
private IShellForm _ShellForm = null;
 
        private WorkItem RootWorkItem
        {
            get { return this.WorkItem.RootWorkItem; }
        }
 
        private void AddServices()
        {
            _ShellForm = ModuleService.GetShellForm();
        }
        private readonly string CLICK_EVENT_NAME = "Click";
 
        private void ExtendMenu()
        {
            #region View Menu
 
            ToolStripMenuItem menuMapView = new ToolStripMenuItem();      //地图视图
            menuMapView.Name = UIExtensionSiteNames.MenuMapView;
            menuMapView.Text = UIExtensionSiteNames.MenuMapView;
            menuMapView.Image = MainViewResource.地图视图;
            WorkItem.Commands[CommandNames.CmdShowMapView].AddInvoker(menuMapView, CLICK_EVENT_NAME);
 
            ToolStripMenuItem menuPropertyView = new ToolStripMenuItem(); //属性视图
            menuPropertyView.Name = UIExtensionSiteNames.MenuPropertyView;
            menuPropertyView.Text = UIExtensionSiteNames.MenuPropertyView;
            menuPropertyView.Image = MainViewResource.属性视图;
            WorkItem.Commands[CommandNames.CmdShowPropertyView].AddInvoker(menuPropertyView, CLICK_EVENT_NAME);
            WorkItem.Commands[CommandNames.CmdShowDrawingView].AddInvoker(MenuDrawingView, CLICK_EVENT_NAME);
 
 
            ToolStripMenuItem menuView = new ToolStripMenuItem();         //视图菜单
            menuView.Name = UIExtensionSiteNames.MenuView;
            menuView.Text = UIExtensionSiteNames.MenuView;
            menuView.DropDownItems.AddRange(new ToolStripItem[] { menuMapView,   menuPropertyView });
 
            WorkItem.UIExtensionSites[NRM.Infrastructure.Interface.Constants.UIExtensionSiteNames.MainMenu].Add<ToolStripMenuItem>(menuView);
            #endregion View Menu
        }
 
        int toolPriority = 1;
        private void ExtendToolStrip()
        {
            #region 视图菜单工具条
            ShellToolStrip toolView = new ShellToolStrip(UIExtensionSiteNames.MenuView);
            _ShellForm.MainToolStrip.Add(toolView);
            int veiwPriority = 1;
 
            //地图视图
            ToolStripItem itemMapView = new ToolStripButton();
            itemMapView.Name = UIExtensionSiteNames.ToolMapView;
            itemMapView.Image = MainViewResource.地图视图;
            itemMapView.ToolTipText = "地图视图";
            ShellToolStripItem tsMapView = new ShellToolStripItem(itemMapView, UIExtensionSiteNames.MenuView, veiwPriority++);
            _ShellForm.MainToolStripItem.Add(tsMapView);
                        WorkItem.Commands[CommandNames.CmdShowLayerView].AddInvoker(itemLayerView, CLICK_EVENT_NAME);
 
            //属性视图
            ToolStripItem itemPropertyView = new ToolStripButton();
            itemPropertyView.Name = UIExtensionSiteNames.ToolPropertyView;
            itemPropertyView.Image = MainViewResource.属性视图;
            itemPropertyView.ToolTipText = "属性视图";
            ShellToolStripItem tsPropertyView = new ShellToolStripItem(itemPropertyView, UIExtensionSiteNames.MenuView, veiwPriority++);
            _ShellForm.MainToolStripItem.Add(tsPropertyView);
            WorkItem.Commands[CommandNames.CmdShowPropertyView].AddInvoker(itemPropertyView, CLICK_EVENT_NAME);
 
            #endregion 视图菜单工具条 
        }

系统启动的时候,会调用ModuleControl里的Run方法

 

三、依赖注入

    

[ServiceDependency]
        public WorkItem WorkItem
        {
            set { _workItem = value; }
            get { return _workItem; }
        }

WorkItem会自动获得。

 

四、MVP模式

一个登入界面的MVP模式。包含Interface层的ILoginView.cs , Presenter层的LoginPersenter.cs  页面层的Winform LoginForm.cs。

 接口层:  

public interface ILoginView : IView
    {
        string UserName { get; }
        string Password { get; }
        void LoginSuccessful();
        void LoginFailed();
        event EventHandler OnLogin;
}

Persenter层

public class LoginPresenter : Presenter
    {
        ILoginView _loginView;
 
        public LoginPresenter( ILoginView view ) : this(view, null)
        {}
 
        public LoginPresenter( ILoginView view, ISessionProvider session ) : base(view, session)
        {
            _loginView = base.GetView<ILoginView>();
            _loginView.OnLogin += new EventHandler(_loginView_OnLogin);
        }
 
        void _loginView_OnLogin(object sender, EventArgs e)
        {
            string userName = _loginView.UserName;
            string password = _loginView.Password;
 
            // Example of managing state without referencing System.Web
            if(this.Session != null && Session["userName"] == null)
            {
                Session["userName"] = userName;
            }
 
            if(userName.Equals("user") && password.Equals("pass"))
            {
                _loginView.LoginSuccessful();
            }
            else
            {
                _loginView.LoginFailed();
            }
        }
    }

 

 

界面层

 

[PresenterType(typeof(LoginPresenter))]-------特性
    public partial class LoginForm : BaseForm, ILoginView
    {
        public LoginForm()
        {
            InitializeComponent();
 
            base.SelfRegister(this);
        }
 
        private void loginButton_Click( object sender, EventArgs e )
        {
            this.OnLogin(this, EventArgs.Empty);
        }
 
        #region ILoginView Members
 
        string ILoginView.UserName
        {
            get { return this.userName.Text; }
        }
 
        string ILoginView.Password
        {
            get { return this.password.Text; }
        }
 
        void ILoginView.LoginSuccessful()
        {
            this.DialogResult = DialogResult.OK;
            this.Close();
        }
 
        void ILoginView.LoginFailed()
        {
            errorLabel.Visible = true;
        }
 
        public event EventHandler OnLogin;
 
        #endregion
    }

MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理,Model提供数据,View负责显示。

 

总结:初探SmartClient,确实让人惊讶,展现出很多魅力,据说他还有很多功能。接触挺久,现在也主要应用它的灵活界面及里面的一些机制。相信随着不断深入,将会发现更多的惊喜。欢迎各位园友拍砖,顺便指点指点,我很想知道,SmartClient中离线操作怎么实现、怎么应用。