摘要: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;
}
该例子主要是在地图上框选出区域内的设备,然后在属性窗口中显示这些设备的信息
整个 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中离线操作怎么实现、怎么应用。