“YbRapidSolution for WinForm”是 YbSoftwareFactory 截至目前发布的功能最强大的代码生成插件,此插件开发的难度超乎想象,应用程序的开发前后断断续续接近三个月,把应用程序源代码转换为 YbSoftwareFactory 的代码生成模板用了2周时间,编写插件源代码则只用了半天,到最后使用 YbSoftwareFactory 重新生成Demo应用程序并在 Visual Studio 中成功运行,更是前后只用了不到 10 分钟。对于今后实现同样效果的应用程序来说,10分钟 >= 3个月,这就是 YbSoftwareFactory 的价值!
本插件生成的界面效果和WPF版本的“YbRapidSolution for WPF”插件类似,但底层架构完全不同,全新的设计赋予了其超凡的功能和特性。最重要的是,生成的代码可是开源的,你可以在 Visual Studio 中不受限制地修改、学习、研究和应用。
为了让广大园友更好地了解 YbSoftwareFactory 的插件编写原理和过程,现把此插件的全部实现代码公开,从中你可看出一个插件的开发是如此的简单:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
using System.Collections.Generic;
using System.Linq;
using Yb.CustomTemplating;
using Yb.DbSchemaReader.DataSchema;
using Yb.Plugin.Base;
using Yb.Utility;
namespace Yb.Plugin.EfCslaDx.WinForm
{
public abstract class EfCslaDxWinPluginRepositoryBase : PluginRepositoryBase
{
private int _totalCount = 0;
private int _currentIndex = 0;
protected virtual int GetShouldBuildCodeNum( int listCount)
{
var templateCount = GetTemplateInfos().Count();
return listCount * templateCount;
}
/// <summary>
/// 生成代码
/// </summary>
/// <param name="dataSource"></param>
/// <param name="templateInfos"></param>
/// <returns></returns>
public override IEnumerable<TemplateInfo> BuildCodes( object dataSource, IEnumerable<TemplateInfo> templateInfos, object dataSourceInfo)
{
// 参数类型转换
var tableInfos = BaseInfoUtility.ObjectToDatabaseTableList(dataSource).Where(c => c.Checked).ToList();
// 生成结果
var templateList = new List<TemplateInfo>();
_totalCount = GetShouldBuildCodeNum(tableInfos.Count);
_currentIndex = 0;
foreach ( var templateInfo in templateInfos)
{
if (!templateInfo.BuildEnable) continue;
// 读模板信息
templateInfo.TemplateContent = FileUtility.ReadFile(templateInfo.TemplateRelativePath,templateInfo.Encoding);
// 判断模板类型,是否每张表都需生成一个模板
if ((templateInfo.Tag & StaticResources.IsTableInfoListOfTemplateArg) == 0)
{
foreach ( var tableInfo in tableInfos)
{
// 复制模板,防止生成后下一个循环被覆盖
var currentTemplateInfo = (TemplateInfo)templateInfo.Clone();
// 生成代码
BuildTableCode( " CurrentTable ", templateList, tableInfo, currentTemplateInfo);
}
}
else
{
// 生成 App.Config 文件
if (templateInfo.ExportFileNameFormatString.Equals( " App.config ", StringComparison.OrdinalIgnoreCase)
||templateInfo.ExportFileNameFormatString.Equals( " Web.config ", StringComparison.OrdinalIgnoreCase))
{
var sourceInfo = dataSourceInfo as DataSourceInfo;
// 创建Web.Config代码
if (sourceInfo != null)
BuildAppConfigCode(templateList, templateInfo, tableInfos, sourceInfo);
}
else
{
// 创建如项目文件等需要传入“表对象集合”为参数的模板代码
BuildTablesCode(templateList, templateInfo, tableInfos);
}
}
}
return templateList;
}
/// <summary>
/// 创建和表有关的代码
/// </summary>
/// <param name="templateArgName"></param>
/// <param name="templateList"></param>
/// <param name="tableInfo"></param>
/// <param name="templateInfo"></param>
private void BuildTableCode( string templateArgName, List<TemplateInfo> templateList, DatabaseTable tableInfo, TemplateInfo templateInfo)
{
try
{
// 代码生成关键代码,根据模板生成代码
templateInfo.ExportContent = Template.Transform(templateInfo.TemplateContent, templateArgName,
tableInfo);
// 更新模板标题,标题也是要生成文件的名称
templateInfo.Title = BaseInfoUtility.ReplaceString(templateInfo.ExportFileNameFormatString,
tableInfo.Name);
templateInfo.ExportRelativePath = BaseInfoUtility.ReplaceString(templateInfo.ExportRelativePathFormatString,
tableInfo.Name);
AddCodeList(templateList, templateInfo);
}
catch (Exception er)
{
NotifyException(templateInfo, er);
}
}
/// <summary>
/// 创建和数据库有关的代码
/// </summary>
/// <param name="templateList"></param>
/// <param name="templateInfo"></param>
/// <param name="tableInfos"></param>
private void BuildTablesCode(List<TemplateInfo> templateList, TemplateInfo templateInfo, List<DatabaseTable> tableInfos)
{
try
{
templateInfo.ExportContent = Template.Transform(templateInfo.TemplateContent, " TableInfos ",
tableInfos);
templateInfo.Title = templateInfo.ExportFileNameFormatString;
templateInfo.ExportRelativePath = templateInfo.ExportRelativePathFormatString;
AddCodeList(templateList, templateInfo);
}
catch (Exception er)
{
NotifyException(templateInfo, er);
}
}
/// <summary>
/// 创建Web.Config 代码
/// </summary>
/// <param name="templateList"></param>
/// <param name="templateInfo"></param>
/// <param name="tableInfos"></param>
private void BuildAppConfigCode(List<TemplateInfo> templateList, TemplateInfo templateInfo, List<DatabaseTable> tableInfos, DataSourceInfo dataSourceInfo)
{
try
{
templateInfo.ExportContent = Template.Transform(templateInfo.TemplateContent, " DataSourceInfo ",
dataSourceInfo);
templateInfo.Title = templateInfo.ExportFileNameFormatString;
templateInfo.ExportRelativePath = templateInfo.ExportRelativePathFormatString;
AddCodeList(templateList, templateInfo);
}
catch (Exception er)
{
NotifyException(templateInfo, er);
}
}
/// <summary>
/// 代码创建后进行事件通知
/// </summary>
/// <param name="templateList"></param>
/// <param name="templateInfo"></param>
private void AddCodeList(List<TemplateInfo> templateList, TemplateInfo templateInfo)
{
templateList.Add(templateInfo);
_currentIndex++;
OnNotifyChanged( new NotifyChangedEventArgs(NotifyType.Seccessful,
string.Format( " 代码 {0} 生成成功 ", templateInfo.Title)
, _currentIndex, _totalCount));
}
/// <summary>
/// 通知代码创建失败
/// </summary>
/// <param name="templateInfo"></param>
/// <param name="er"></param>
private void NotifyException(TemplateInfo templateInfo, Exception er)
{
_currentIndex++;
OnNotifyChanged( new NotifyChangedEventArgs(NotifyType.Error,
string.Format( " 代码 {0} 生成失败,模板名称:{1}。\r\n{2} ", templateInfo.Title,templateInfo.TemplateRelativePath, er.Message),
_currentIndex, _totalCount));
}
public override IEnumerable<TemplateInfo> GetTemplateInfos()
{
return StaticResources.GetTemplateInfos();
}
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Text;
using Yb.CustomTemplating;
using Yb.Plugin.Base;
using Yb.Utility;
namespace Yb.Plugin.EfCslaDx.WinForm
{
[PluginMetadataAttribute(Name = " 实体代码生成 ",
Description = " 生成 Entity Framework Code First 实体对象 ",
DisplayOrder = 5,
ImageUri = " pack://application:,,,/Yb.Plugin.EfCslaDx.WinForm;component/Images/Win_EF_Entity_64x64.png ",
LargeImageUri = " pack://application:,,,/Yb.Plugin.EfCslaDx.WinForm;component/Images/Win_EF_Entity_64x64.png ",
CodeOutputMode = CodeOutputMode.PreView)]
[Export(StaticResources.PluginGroupKey, typeof(IPluginRepository))]
public class EfCslaDxWinEntitiesPluginRepository : EfCslaDxWinPluginRepositoryBase
{
public override IEnumerable<TemplateInfo> GetTemplateInfos()
{
var templateInfo = base.GetTemplateInfos();
// 通过 Tag 来计算是否需要使用该模板
return templateInfo.Where(c => c.BuildEnable && (c.Tag & StaticResources.EntitiesPluginTemplateTag) > 0);
}
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Text;
using Yb.Plugin.Base;
using Yb.Plugin.EfCslaDx.WinForm;
namespace Yb.Plugin.EfCslaDx.WinForm
{
[PluginMetadataAttribute(Name = " CSLA业务逻辑层代码 ",
Description = " 生成基本 CSLA.NET 的业务逻辑层代码 ",
DisplayOrder = 15,
ImageUri = " pack://application:,,,/Yb.Plugin.EfCslaDx.WinForm;component/Images/CSLA.png ",
LargeImageUri = " pack://application:,,,/Yb.Plugin.EfCslaDx.WinForm;component/Images/CSLA.png ",
CodeOutputMode = CodeOutputMode.PreView)]
[Export(StaticResources.PluginGroupKey, typeof(IPluginRepository))]
public class EfCslaDxWinBusinessPluginRepository : EfCslaDxWinPluginRepositoryBase
{
/// <summary>
/// 获取业务层模板
/// </summary>
/// <returns></returns>
public override IEnumerable<TemplateInfo> GetTemplateInfos()
{
var templateInfo = base.GetTemplateInfos();
return templateInfo.Where(c => c.BuildEnable && (c.Tag & StaticResources.BusinessPluginTemplateTag) > 0);
}
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Text;
using Yb.Plugin.Base;
namespace Yb.Plugin.EfCslaDx.WinForm
{
[PluginMetadataAttribute(Name = " 数据访问层代码 ",
Description = " 生成数据访问层代码 ",
DisplayOrder = 10,
ImageUri = " pack://application:,,,/Yb.Plugin.EfCslaDx.WinForm;component/Images/Win_EF_Respository_64x64.png ",
LargeImageUri = " pack://application:,,,/Yb.Plugin.EfCslaDx.WinForm;component/Images/Win_EF_Respository_64x64.png ",
CodeOutputMode = CodeOutputMode.PreView)]
[Export(StaticResources.PluginGroupKey, typeof(IPluginRepository))]
public class EfCslaDxWinRepositoriesPluginRepository : EfCslaDxWinPluginRepositoryBase
{
/// <summary>
/// 获取界面层模板
/// </summary>
/// <returns></returns>
public override IEnumerable<TemplateInfo> GetTemplateInfos()
{ var templateInfo = base.GetTemplateInfos();
return templateInfo.Where(c => c.BuildEnable && (c.Tag & StaticResources.RepositoryPluginTemplateTag) > 0);
}
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Text;
using Yb.Plugin.Base;
using Yb.Plugin.EfCslaDx.WinForm;
namespace Yb.Plugin.EfCslaDx.WinForm
{
[PluginMetadataAttribute(Name = " WinForm界面层代码 ",
Description = " 生成DevExpress界面层代码 ",
DisplayOrder = 20,
ImageUri = " pack://application:,,,/Yb.Plugin.EfCslaDx.WinForm;component/Images/DXv2.png ",
LargeImageUri = " pack://application:,,,/Yb.Plugin.EfCslaDx.WinForm;component/Images/DXv2.png ",
CodeOutputMode = CodeOutputMode.PreView)]
[Export(StaticResources.PluginGroupKey, typeof(IPluginRepository))]
public class EfCslaDxWinUIPluginRepository : EfCslaDxWinPluginRepositoryBase
{
/// <summary>
/// 获取界面层模板
/// </summary>
/// <returns></returns>
public override IEnumerable<TemplateInfo> GetTemplateInfos()
{
var templateInfo = base.GetTemplateInfos();
return templateInfo.Where(c => c.BuildEnable && (c.Tag & StaticResources.WinFormPluginTemplateTag) > 0);
}
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Data.SqlClient;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Yb.Plugin.Base;
using Yb.Utility;
namespace Yb.Plugin.EfCslaDx.WinForm
{
[PluginMetadataAttribute(Name = " 解决方案 ",
Description = " 生成Castel数据访问层,Catel视图模型层,DevExpress界面层代码的解决方案 ",
DisplayOrder = 100,
ImageUri = " pack://application:,,,/Yb.Plugin.EfCslaDx.WinForm;component/Images/Win.png ",
LargeImageUri = " pack://application:,,,/Yb.Plugin.EfCslaDx.WinForm;component/Images/Win.png ",
CodeOutputMode = CodeOutputMode.File)]
[Export(StaticResources.PluginGroupKey, typeof(IPluginRepository))]
public class EfCslaDxWinSolutionPluginRepository : EfCslaDxWinPluginRepositoryBase
{
private const string ZipFileRelativePath = @" Plugin\Yb.Plugin.EfCslaDx.WinForm\ZipFiles\YbRapidSolution.Win.zip ";
protected override int GetShouldBuildCodeNum( int listCount)
{
var templateCount = GetTemplateInfos().Count();
return listCount * (templateCount - 12)+ 12;
}
/// <summary>
/// 解压文件到指定路径
/// </summary>
/// <param name="path"> 解压路径 </param>
public override void BeforeBuild( string path)
{
OnNotifyChanged( new NotifyChangedEventArgs(NotifyType.Infomation, " 正在解压文件,请稍候 "));
// 解压文件到指定路径
FileUtility.ExtractFileTo(ZipFileRelativePath, path);
OnNotifyChanged( new NotifyChangedEventArgs(NotifyType.Infomation, " 解压文件结束 "));
}
/// <summary>
/// 获取本插件所需的模板信息
/// </summary>
/// <returns></returns>
public override IEnumerable<TemplateInfo> GetTemplateInfos()
{
var templateInfo = base.GetTemplateInfos();
return templateInfo.Where(c => c.BuildEnable && (c.Tag & StaticResources.SolutionPluginTemplateTag) > 0);
}
/// <summary>
/// 安装和权限有关的数据库脚本
/// </summary>
/// <param name="dataSourceInfo"></param>
public override void AfterBuild( object dataSourceInfo)
{
if (dataSourceInfo == null) return;
var sourceInfo = dataSourceInfo as DataSourceInfo;
if (sourceInfo == null) return;
var connStr = sourceInfo.DataSourceString;
OnNotifyChanged( new NotifyChangedEventArgs(NotifyType.Infomation, " 正在安装数据库脚本 "));
try
{
// 执行创建表的脚本文件
ExecuteSqlServerDbScript(connStr);
// 进度通知
OnNotifyChanged( new NotifyChangedEventArgs(NotifyType.Infomation, " 数据库脚本处理完成 "));
}
catch (Exception er)
{
// 进度通知
OnNotifyChanged( new NotifyChangedEventArgs(NotifyType.Infomation, string.Format( " 数据库脚本安装失败,{0} ", er.Message)));
}
}
private void ExecuteSqlServerDbScript( string connStr)
{
var smoUtiltiy = new SmoUtility(connStr);
var tableInfos = smoUtiltiy.GetTableInfos();
// 如果没有表信息或者不包含默认的和权限有关的表,则执行数据库表初始化脚本
if (tableInfos == null || tableInfos.Select(c => c.Name).Contains(StaticResources.MembershipConfigTableName))
{
OnNotifyChanged( new NotifyChangedEventArgs(NotifyType.Infomation, " 未安装数据库脚本,相关表已存在 "));
return;
}
// 创建相应表的脚本
string providerInstallScript = FileUtility.ReadFile( @" Plugin\Yb.Plugin.EfCslaDx.WinForm\Templates\ProviderInstallScript.sql ");
SqlServerDataUtility.ExecuteSqlServerDbScript(connStr, providerInstallScript);
OnNotifyChanged( new NotifyChangedEventArgs(NotifyType.Infomation, " 安装数据库脚本成功,应用程序默认登录名:admin,密码:123456 "));
}
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Data;
using System.Linq;
using System.Text;
using Yb.Data;
using Yb.Plugin.Base;
using Yb.Utility;
namespace Yb.Plugin.EfCslaDx.WinForm
{
[PluginGroupAttribute(
Name = " Ef Csla Dx for WinForm ",
Description = " 生成 EF 数据访问层,CSLA.NET 业务逻辑层,DxV2 界面层的 WinForm 代码及解决方案 ",
DisplayOrder = 5,
DataSourceType = DataSourceType.Database,
DataSourceName = DataSourceName.SqlDataSource | DataSourceName.AccessDataSource,
ImageUri = " pack://application:,,,/Yb.Plugin.EfCslaDx.WinForm;component/Images/WinFormGroup.png ",
LargeImageUri = " pack://application:,,,/Yb.Plugin.EfCslaDx.WinForm;component/Images/WinFormGroup.png ",
NavigationGroup = " Ef Csla Dx 代码生成插件 ")]
[Export( typeof(IPluginGroupRepository))]
public class EfCslaDxWinPluginGroupRepository : IPluginGroupRepository, IPartImportsSatisfiedNotification
{
[ImportMany(StaticResources.PluginGroupKey, AllowRecomposition = true)]
public IEnumerable<Lazy<IPluginRepository, IPluginMetadata>> LazyPluginRepositories { get; set; }
public void OnImportsSatisfied()
{
LazyPluginRepositories = LazyPluginRepositories.OrderBy(c => c.Metadata.DisplayOrder);
}
/// <summary>
/// 创建数据源
/// </summary> <param name="arg"></param>
/// <returns></returns>
public object CreateDataSource( object arg)
{
if (!(arg is DataSourceInfo))
{
throw new ArgumentException( " 参数不是有效的 DataSourceInfo 类型 ", " arg ");
}
var dataSourceInfo = arg as DataSourceInfo;
if (dataSourceInfo == null) throw new ArgumentNullException( " arg ", " DataSourceInfo 参数不能为空 ");
var schemaUtil = new DbSchemaUtility();
// 获取表信息
try
{
var tableInfos = schemaUtil.GetDbTables(dataSourceInfo);
// 过滤掉和权限有关的表
if (tableInfos != null && tableInfos.Count > 0)
tableInfos = tableInfos.Where(c => !StaticResources.SecurityDbTablesName.Contains(c.Name)).ToList();
return tableInfos;
}
catch (Exception er)
{
throw new DataException( string.Format( " 获取表信息失败,{0} ", er.Message));
}
}
/// <summary>
/// 初始化模板
/// </summary>
/// <returns></returns>
public IEnumerable<TemplateInfo> GetTemplateInfos()
{
return StaticResources.GetTemplateInfos();
}
}
}
有图有真相:
1、生成代码后使用Visual Studio打开即可直接调试运行,甚至无需配置数据库连接字符串等等。
YbSoftwareFactory 中的 “YbRapidSolution for WinForm” 插件
生成的解决方案运行后的主界面效果图如下:
2、数据访问层使用Entity Framework,一键生成 Code First 代码,大大提高了二次开发的灵活性。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
using System.ComponentModel.Composition.Hosting;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.ModelConfiguration.Conventions;
using System.Reflection;
using YbRapidSolution.Data;
namespace YbRapidSolution.Entities
{
/// <summary>
/// Object context
/// </summary>
public class YbObjectContext : YbDbContext
{
public YbObjectContext( string nameOrConnectionString)
: base(nameOrConnectionString)
{
this.Database.CompatibleWithModel( false);
// Database.SetInitializer(
// new DropCreateDatabaseIfModelChanges<YbObjectContext>());
Database.SetInitializer( new CreateDatabaseIfNotExists<YbObjectContext>());
}
public IDbSet<Categories> Categories { get; set; }
public IDbSet<Customers> Customers { get; set; }
public IDbSet<Employees> Employees { get; set; }
public IDbSet<Orders> Orders { get; set; }
public IDbSet<Products> Products { get; set; }
public IDbSet<Shippers> Shippers { get; set; }
public IDbSet<Suppliers> Suppliers { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// 使用Attribute进行配置,则取消注释如下代码
// ContextConfiguration(modelBuilder);
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
this.Configuration.LazyLoadingEnabled = true;
base.OnModelCreating(modelBuilder);
}
private void ContextConfiguration(DbModelBuilder modelBuilder)
{
var contextConfiguration = new ContextConfiguration();
var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
var container = new CompositionContainer(catalog);
container.ComposeParts(contextConfiguration);
foreach ( var configuration in
contextConfiguration.Configurations)
{
configuration.AddConfiguration(
modelBuilder.Configurations);
}
}
}
}
3、支持 N-Tier 层部署,简单地修改配置文件就可在本地部署和 N-Tier 层部署之间切换,灵活性超强。同时,服务层无需额外编写复杂的代码,只需你去配置。如下为服务层的文件结构,够简单吧:-)
4、支持对象状态跟踪,能自动识别对象是否被修改,修改后窗体标题使用“*”标记,并且未保存直接点击关闭按钮时将会自动弹出保存确认对话框。
5、多达 40 种界面主题,除了炫还是炫。。。
6、每个用户可以单独设置窗体主题和布局的设置选项。所有窗体的主题、布局都能为每个登录用户单独、自动进行保存,用户下次登录后可自动恢复这些主题和布局,超强的用户体验让你过目难忘。
7、每个List列表视图模块可快速对本模块的界面进行定制并为每个用户单独保存界面布局并在下次登录后自动加载。
8、List列表视图支持Grid网格布局和Card卡片布局,用户可以自由切换,下次登录时将为该模块自动加载相应的界面布局模式。
视图切换:
切换在Card卡片视图模式下具有动画效果的旋转模式,非常的Cool:
Card卡片模式下的水平布局方式:
9、Card卡片视图支持多种模式切换,可以通过工具条进行定制,每个登录用户可在运行时单独对界面布局进行设计并保存,还是让用户来设计吧。
10、Detail明细视图同样支持用户在运行时对指定模块的界面布局进行个性化设计,下次该用户重新登录后能自动恢复该用户设计的模块界面布局。
11、类似 VS 的可拖拽、浮动和停靠窗口:
12、生成的代码自动处理关联,看看下拉框的例子。
13、超级强悍的打印预览与导出功能
Grid表格模式下的打印预览效果图
Card卡片模式下的打印预览效果图
导出格式多样
14、生成的代码自动集成了数据有效性验证,当前使用的验证方式是.NET Framework 已集成的“Data Annotations”验证。
自动生成的验证逻辑如下,没错就是这么简单:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
editObject = CreateNewObject();
var validateRule = ValidationRulesHelper.CslaValidationRule(editObject);
ValidationProvider.SetValidationRule(editCategoryID, validateRule);
ValidationProvider.SetValidationRule(editCategoryName, validateRule);
ValidationProvider.SetValidationRule(editDescription, validateRule);
数据验证失败的界面效果图如下:
15、提供同时支持N-Tier层部署和本地部署的身份验证、授权和权限管理组件,统一的 API 底层接口让你可以在Web、WPF、Silverlight和WinForm的任何项目中同时并轻松调用,并且你还可随意对权限的层次进行设计和扩展,具有极强的灵活性和通用性。
角色权限管理模块支持细粒度的操作权限:
用户角色管理界面:
16、生成的代码集成了支持 N-Tier 层部署和本地部署的可缓存的数据字典管理,让你更方便、快速、高效地进行后续的个性化开发。同样,提供的 API 接口让你可以在任何类型的项目中同时轻松调用。。。
![](https://i-blog.csdnimg.cn/blog_migrate/55616b26c6458eb3f683aeda5e08669f.png)
![](https://i-blog.csdnimg.cn/blog_migrate/bcbbd9c98780146aec333c11749b052a.png)
17、提供非常灵活的依赖注入接口,你可自由设置你熟悉的依赖注入工具,如下配置使用了 Autofac 依赖注入工具。
注:Autofac是默认的依赖注入工具
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
using AutofacContrib.CommonServiceLocator;
using Microsoft.Practices.ServiceLocation;
using YbRapidSolution.Core.Infrastructure;
using YbRapidSolution.Data;
using YbRapidSolution.Entities;
namespace YbRapidSolution.Win
{
public class AutofacBootStrapper : CommonBootStrapper
{
protected override IServiceLocator CreateServiceLocator()
{
var builder = new ContainerBuilder();
RegisterTypes(builder);
var container = builder.Build();
return new AutofacServiceLocator(container);
}
private static void RegisterTypes(ContainerBuilder builder)
{
builder.Register(c=> new YbObjectContext( " YbRapidSolution ")).As<IDbContext>();
builder.RegisterGeneric( typeof(EfRepository<>)).As( typeof(IRepository<>));
}
}
}
18、快速查询
19、异步加载模式,防止界面假死
20、集成Log4net日志,方便你进行程序调试。
近期将在下一章推出“YbRapidSolution for WinForm”插件所生成解决方案的架构介绍,并提供本 Demo 应用程序的下载地址,可亲自下载体验实际运行效果,请继续关注。