Compare commits

...

213 Commits

Author SHA1 Message Date
Argo-Tianyi
481be3a5b2 release: publish 5.0.28 2021-04-29 17:20:23 +08:00
Argo
4fd5a23ecd !1366 fix(#I3OVJC): resolve Checkbox not show invalid message when enable ValidateAllProperties on ValidateForm
* fix: 修复验证所有属性时 CheckboxList 无验证问题
* refactor: 代码复用使用 Validate 方法
* refactor: 提炼 Validate 方法代码复用
* Merge branch 'dev' into dev-checkboxlist
* refactor: ValidateForm 验证跳过集合
* refactor: 使用 OfType 代替 Where 过滤条件
* refactor: 移除 sealed 关键字
2021-04-29 17:13:38 +08:00
Argo
a4d112e0a4 !1365 fix(#I3OUQZ): validate form support complex class validation function
* revert: 移除表单验证过滤条件
2021-04-29 16:13:40 +08:00
Argo
305283993c !1364 docs(#I3OTB9): update table detail row sample code menu text
* docs: 更新英语下明细行菜单
2021-04-29 13:25:28 +08:00
Argo
e6bdaae6ce !1363 feat(#I3OT83): sub class support new keyword override parent class property
* feat: 内部使用 GetProperty 方法统一使用 GetProperties
2021-04-29 13:22:57 +08:00
Argo
ce64046690 !1362 feat(#I29FLZ): redesign SideMenu UI support float submenu on Collapsed mode
* feat: 增加侧栏收缩状态下级联选中功能
* revert: 移除间隙防止鼠标在间隙时菜单消失
* style: 微调收缩模式下子菜单间隙
* feat: 收缩模式下移除缩进功能
* style: 更新收缩模式下子菜单展开箭头样式
* feat: 微调收缩状态下样式
* style: 更新样式
* Merge branch 'dev' into dev-menu-collapse
* chore: 更新 Collapsed 状态下脚本
* feat: 移除 SideMenu 的 IsCollapsed 参数
* feat: 增加收缩状态下样式
* style: 增加收缩图标样式
* docs: 更新动态更新菜单数据源示例
* scripts: 支持动态更新数据源
* fix: 修复变量错误问题
* Merge branch 'dev' into dev-menu-collapse
* refactor: 移除 bugs 文件
* Merge branch 'dev' into dev-menu-collapse
* feat: 菜单增加全部展开功能
* feat: 增加自动展开功能
* docs: 增加全部展开按钮
* chore: 增加全部展开资源文件
* scripts: 更新脚本支持全部展开
* fix: Tree 组件内 Checkbox 禁止显示 Label
* chore: 规范化资源文件
* refactor: 更新侧边栏菜单示例
* style: 更新侧边栏菜单样式
* docs: 删除 menus 资源文件
* docs: Menus 示例文档增加多语言支持
* refactor: 移除 IndentSize 属性
* perf: 提高性能
* refactor: 精简代码
* feat: 增加菜单初始化功能
* refactor: 移除 DisabledNavigation 属性
* style: 精简样式
* feat: 更新过期方法提示信息
* feat: TopMenu 增加单独使用保护
* refactor: 格式化代码
* docs: 更新菜单数据源增加异步模拟方法
* feat: 修复顶栏下拉菜单无法收起问题
* feat: 增加空集合保护
* feat: 增加默认构造函数
* feat: 从新设计 MenuItem Items 属性
* fix: 修复顶栏 dropdown 无法收缩问题
* feat: 微调顶栏带图标菜单样式
* docs: 增加资源文件
* wip
* style: 增加顶栏宽度设置
* feat: 顶栏 MenuLink 移除前后图标占位
* feat: 增加顶栏切换菜单动画效果
* refactor: 更新顶栏菜单
* feat: 侧栏增加禁用支持
* feat: 顶栏不进行缩进操作
* refactor: 移除不用的方法
* chore: 更新样式
* feat: 增加 MenuItem 扩展方法
* refactor: 增加禁用样式
* chore: 精简样式 nav-link-text 更改为 text
* style: 移除顶端间隙
* refactor: 微调 badge 顺序
* scripts: 增加首次加载展开节点功能
* refactor: 精简样式
* feat: 防止 SideMenu 独立使用
* refactor: 精简样式
* chore: 精简 javascript 脚本
* docs: 更新样式表顺序
* docs: 更新示例文档
* feat: 增加菜单手风琴功能切换
* feat: 根节点不缩进
* style: 微调菜单左右间距
* chore: 增加资源文件
* chore: 更新脚本
* style: 减少右侧间隙
* chore: 完善手风琴效果
* feat: 增加递归设置 Indent 方法
* docs: 微调侧边栏菜单宽度为 300
* feat: 设置几个菜单匹配方式为 MatchLink.All
* chore: 更新侧边栏菜单样式
* feat: Menu 组件增加侧边栏脚本调用方法
* feat: MenuLink 右侧箭头占位
* chore: 更新侧边栏右侧箭头样式
* chore: 增加侧边栏菜单脚本
* docs: 更新资源文件行设置菜单
* style: 更新菜单背景色
* feat: Menu 组件增加缩进参数默认 16
* refactor: 重构侧边栏菜单
* refactor: 更新代码使用 Enumerable.Empty
* feat: 增加缩进功能
* feat: 增加 Indent 属性
* style: 增加菜单集合右侧小箭头样式
* style: 更新样式
* docs: 更新注释文档
* Merge branch 'dev' into dev-Menu
* Merge branch 'dev' into dev-Menu
* fix: 修复翻页或者更改每页显示条目数后 ShowTips 失效问题
* Merge branch 'dev' into dev-Menu
* wip: 侧边栏菜单优化(未完成)
* refactor: remove OnCollapsed default value
* feat: SideMenu add IsCollapsed parameter
2021-04-29 12:46:25 +08:00
Argo
d7547b76a2 !1361 docs(#I3OGXE): add microsoft docs learn
* docs: 增加 mvp 链接
* docs: 更新 ms-docs 文章
* chore: 增加图片
2021-04-27 21:17:49 +08:00
Argo
dbaebf2c2e !1360 docs(#I3OER7): add ad external link
* chore: 更新 ad 广告脚本顺序与样式
* chore: 更新广告样式
* chore: 增加样式
* chore: 增加 banner
* chore: 增加流量脚本
2021-04-27 15:55:36 +08:00
Argo
8fd8689969 !1359 feat(#I3ODK8): TryConvertTo throw exception when type is string
* fix: 修复 TryConvertTo 报错问题
2021-04-27 14:06:33 +08:00
Argo
b038291382 !1358 feat(#I3OAUQ): Select support Placeholder
* docs: 更新 Select 绑定可为空类型示例
* feat: 可为空类型首选项支持 PlaceHolder 设置
2021-04-26 21:45:29 +08:00
Argo
a0fb963bc3 !1357 feat(#I3O7QY): add TryConvertTo string extensions method
* refactor: 增加错误保护
* test: 更新输出日志信息
* refactor: 删除不用的代码
* feat: 增加 TryConvertTo 方法
* test: 更新性能测试
2021-04-26 15:04:58 +08:00
刘亮
3b37589ef9 !1356 feat(#I3O56M): CheckboxList MultiSelect support List<Guid> data
* Merge branch 'dev' of gitee.com:LongbowEnterprise/BootstrapBlazor into dev
* fix checkboxlist and multiselect when bind-value is a List<guid>
* update bind to new property
2021-04-26 10:53:08 +08:00
Argo
4e082ca7da !1355 fix(#I3HWSW): throw exception when use new keyword change property Type in sub class
* fix: 修复获取属性时遇到 new 关键字重写属性报错问题
2021-04-26 00:39:48 +08:00
刘亮
7549240abf !1354 fix(#I3HWSW): throw exception when use new keyword change property Type in sub class
* update bind to new property
2021-04-26 00:14:52 +08:00
阿凡达
f0f2c733da !1353 docs: update SwalCategory xml doc
* update src/BootstrapBlazor/Components/SweetAlert/SwalOption.cs.
2021-04-25 21:34:56 +08:00
Argo
35c550bfa3 !1352 fix(#I3O3QP): checkbox label should not shown in Tree component
* fix: Tree 组件内 Checkbox 禁止显示 Label
2021-04-25 19:38:03 +08:00
Argo
5638f86466 !1351 fix(#I3MJKW): resolve throw exception InputUpload component
* release: publish 5.0.28-beta01
* fix: 修复 InputUpload 抛异常问题
2021-04-23 20:24:20 +08:00
Argo
795d39a07d !1350 fix(#I3MC54): resolve Pagination component not render after change ItemsPerPage source
* Merge branch 'dev-docs' into dev-fix
* fix: 每页显示数量变更时重新刷新组件
* chore: 更新依赖组件 5.0.18
2021-04-22 18:39:12 +08:00
Argo
41a1382e76 !1349 chore(#I3NMBT): extensions upgrade to 5.0.18
* chore: 扩展组件更新到 5.0.18
* docs: 更新英文 main 编译状态链接
2021-04-22 14:58:39 +08:00
Argo-Cloud
ac4e5c03c6 release: publish 5.0.27 2021-04-22 14:37:18 +08:00
Argo
28aacd755f !1348 feat(#I3NM1W): redesign Transfer component support Validation
* docs: 更新异步加载数据源示例
* feat: 支持客户端验证
* style: 增加客户端验证样式
* Merge branch 'dev-docs' into dev-transfer
* docs: 增加资源文件
* docs: 删除资源文件
* !1344 docs(#I3NF1P): Menu support localization
* docs: 更新示例文档
* feat: 支持表单验证
* perf: 未双向绑定时减少 invoke 调用
* style: 增加 Transfer 项目样式防止折行
* docs: 更新 github action main 分支状态
* docs: 更新资源文件
* docs: 更新 action 链接
2021-04-22 14:35:21 +08:00
Argo
bebdf4e7c6 !1346 docs(#I3NFM4): update readme.md
* chore: 增加 build actions
* docs: 更新 readme 文档
2021-04-21 16:30:46 +08:00
Argo
2fb689e987 !1345 fix(#I3NF8X): InputNumber throw exception in wasm mode on Centos server
* fix: 修复 wasm 模式下 InputNumber 报错问题
2021-04-21 16:06:59 +08:00
Argo
98f945121b !1344 docs(#I3NF1P): Menu support localization
* docs: 更新资源文件
* docs: Table 支持多语言
* docs: 数据组件支持多语言
* docs: 表单组件支持多语言
* docs: 消息组件支持多语言
* docs: 导航菜单支持多语言
* docs: 布局组件多语言
* docs: 增加组件总览多语言
* docs: 增加快速上手英文菜单
* refactor: 更新首页响应式布局
* style: 微调按钮宽度
* chore: BaseLayout 增加 c# 代码
* chore: 增加资源文件
* style: 更新 theme z-index 值
* feat: CultureChooser 组件支持本地化
* Merge branch 'dev' into dev-localizer
* refactor: WIP
2021-04-21 15:52:58 +08:00
Argo
4be6ccbc92 !1343 docs(#I3N1EB): update download sample code
* docs: 更新示例
* refactor: 格式化文档
* chore: 打包 js 文件
2021-04-20 17:03:08 +08:00
j4587698
bc0ba0733c !1342 feat(#I3J3DD): Download component support URL link feature
* 下载组件增加获取url的功能
2021-04-20 16:15:58 +08:00
Argo
d91bd93554 !1341 docs(#I3MZ20): update async get data from webapi cascading update select Items sample code
* release: publish 5.0.27-beta07
* docs: 更新异步级联更新下拉框示例
2021-04-20 12:58:09 +08:00
Argo
818bea5062 !1340 fix(#I3IA28): increase delay interval to 300 prevent removeChild throw exception
* fix: 修复 removeChild 客户端脚本错误
2021-04-20 12:40:50 +08:00
Argo
b12513bbe6 !1339 fix(#I3MZ03): checkbox component show label on transfer panel inside ValidateForm
* fix: Transfer 内部 Checkbox 为针对 ValidateForm 适配问题
2021-04-20 12:35:48 +08:00
Argo
314b837d63 !1338 fix(#I3MR1F): resolve Option not render in Select component
* fix: Select 组件 Options 不能加载问题
2021-04-19 20:07:22 +08:00
Argo
253618307e !1337 fix(#I3MNBI): remove duplicate OnClickWithoutRender callback
* refactor: 移除重复的 OnClickWithoutRender
2021-04-19 18:40:30 +08:00
Argo-Cloud
ede70e7010 release: publish 5.0.27-beta04 2021-04-19 15:39:52 +08:00
Argo
22b472fab6 !1336 refactor(#I3MDXO): redesign Select component
* refactor: 更新 Dropdown 组件适配 SelectBase 改动
* docs: 更新 Select 示例代码
* refactor: 重构 SelectBase 精简代码
* refactor: 移除 bind-Items 双向绑定
2021-04-19 15:38:30 +08:00
Argo
bbc442b0f6 !1335 feat(#I3LVCV): Select support bind-Items feature
* docs: 更新 Select 级联参数示例
* refactor: 重构代码
* feat: 更新首次加载触发条件
* feat: 增加 Items 双向绑定支持
* docs: 更新过期提示信息
* refactor: 增加 Items 为空检查
* refactor: 增加 Items 双向绑定支持
2021-04-19 00:31:49 +08:00
Argo
c6a51e3e29 !1334 fix(#I3LVBZ): MultiSelect OnParameterSet should check CurrentValueAsString
* docs: 更改级联参数示例
* fix: 修复级联更改数据源不正确问题
2021-04-19 00:30:21 +08:00
Argo
866824d7ea !1333 refactor(#I3LS7P): multi-select change Items type to IEnumerable<T>
* docs: 更新 MultiSelect 组件示例文档
* feat: MultiSelect 数据源更改为 IEnumerable 支持 out 关键字
2021-04-18 22:50:50 +08:00
Argo
bce5422c24 !1332 refactor(#I3LFLZ): remove MultiSelect Items bind
* release: publish 5.0.27-beta03
* docs: 更新 OnSelectedItemsChanged 方法示例
* feat: 移除 Items 双向绑定
* Revert "feat: 移除 OnSelectedItemsChanged 回调"
* docs: 更新 MultSelect 示例文档
* feat: 移除 OnSelectedItemsChanged 回调
2021-04-18 17:29:41 +08:00
Argo
b81130da87 !1331 docs(#I3L2BR): add catch for ExampleExtensions
* docs: 获取源码方法增加 TaskCancelException 捕获
2021-04-18 15:53:53 +08:00
Argo
cc0e92a511 !1330 refactor(#I3L26F): Modal disposing changed to async
* refactor: 增加 TaskCanceledException 保护
* refactor: Modal 使用异步销毁方法
2021-04-18 15:51:42 +08:00
Argo
7166fceed1 !1329 fix(#I3KWF7): button submit type not work in ValidateForm on IsAsync mode
* fix: 修复表单提交按钮异步操作时图标不变化
2021-04-18 14:21:48 +08:00
Argo
69d26ba5af !1328 feat(#I3KWB0): update FormatValueString method in MultiSelect
* refactor: MultiSelect 内部使用缓存提高性能
* docs: 更新 MultiSelect 示例文档
* fix: MultiSelect 内部支持异步赋值
2021-04-18 14:20:07 +08:00
Argo
6246d0792f !1327 feat(#I3JCAS): add stream parameter override method on Download component
* feat: 增加一个流参数重载方法
* docs: 更新 Download 组件示例
* refactor: 优化 Download 组件代码
* docs: 更新 Download 组件示例代码
* refactor: 重构代码增加注释
* chore: 格式化脚本
* docs: 增加 Option 注释
2021-04-17 16:32:11 +08:00
Argo
c608060f44 !1326 feat(#I3J9XZ): MultSelect support bind-Items
* release: publish 5.0.27-beta02
* docs: 更新 MultiSelect 示例
* feat: MultiSelect 组件 Items 增加双向绑定支持
* docs: 更新 MultiSelect 示例文档
* refactor: 更新 SelectedItems 内部逻辑
2021-04-17 14:20:16 +08:00
Argo
b85a89a671 !1325 fix(#I3J8UD): sub class of ValidationAttribute not working on ValidateForm
* fix: 修复 Validation 派生类不生效问题
2021-04-17 11:56:23 +08:00
j4587698
08b3745b8d !1322 feat(#I3J3DD): add Download component
* 添加示例页面
* 增加Download组件
2021-04-17 10:22:09 +08:00
Argo
2d57844dce !1324 fix(#I3J5CT): throw client javascript exception can't find $.initTheme function when reboot app
* chore: 增加 version 关键字
* chore: 微调脚本加载顺序
2021-04-16 15:22:11 +08:00
Argo
234e7b3f17 !1323 feat(#I3J5C9): Transfer support bind-Items feature
* chore: 增加 SetItems 方法过期标签
* docs: 微调样式
* refactor: 优化性能
* docs: 更新双向绑定示例
* fix: 修复全选为过滤搜索条件问题
* docs: 更新示例代码独立数据源
* style: 微调搜索栏样式
* docs: 更新示例文档
* docs: 增加资源文件
* refactor: 重构内部逻辑
* refactor: 移除基类
* docs: 更新更改数据源示例
* feat: 增加 SetItems 方法
2021-04-16 15:19:08 +08:00
Argo
71915a8669 !1321 feat(#I3J1VX): Display support Nullable<bool> and Null
* fix: 修复 bool? 类型与 Null 值显示不正确问题
2021-04-16 00:34:24 +08:00
Argo-Cloud
b57b70855e release: publish 5.0.27-beta01 2021-04-15 19:32:21 +08:00
Argo
aaa8d5f2d6 !1320 fix(#I3J0GH): render twice in Dialog component
* fix: 移除 StateHasChanged 方法
2021-04-15 17:56:24 +08:00
Argo
7c24ec65a2 !1319 fix(#I3IXZW): Button IsAsync function not working in 5.0.26
* fix: 按钮异步提交功能丢失
* refactor: wip
2021-04-15 14:08:15 +08:00
Argo
a7b3bf4105 !1318 feat(#I3IWEU): extensions upgrade version to 5.0.17
* chore: 部署脚本增加 dotnet restore
* chore: 扩展类版本更新到 5.0.17
* chore: 更新 sdk 到  5.0.202
2021-04-15 11:18:51 +08:00
Argo-Cloud
1feb75425e release: publish 5.0.26 2021-04-15 10:46:22 +08:00
Argo
8b1fd0cc7c !1317 fix(#I3IVZV): Avatar GetUrlAsync not working after render
* fix: 修复 GetUrlAsync 不生效问题
2021-04-15 10:46:19 +08:00
Argo
e49bfaab5f !1316 fix(#I3IVUS): should be Show Text value on Display component when provider Data parameter
* fix: 修复 Display 组件提供 Data 后显示内容不正确问题
2021-04-15 10:35:57 +08:00
Argo
1711200a39 !1315 fix(#I3ITV3): CloseOtherTabs and CloseAllTabs not rerender UI
* release: publish 5.0.26-beta08
* fix: Tab 公开方法 CloseOtherTabs 与 CloseAllTabs 未刷新 UI 问题
2021-04-14 19:13:26 +08:00
Argo
22e56afff6 !1314 feat(#I3ISWR): add OnCollapseChanged callback on Collapse component
* docs: 增加 Collapse 点击事件回调示例
* feat: 增加 CollapseItem 点击事件
* feat: 增加 Collapse 状态回调方法
2021-04-14 17:02:35 +08:00
Argo
fe9d30a0a2 !1313 feat(#I3IQKI): add TitleColor parameter on Collapse component
* docs: Collpase 增加 TitleColor 示例
* feat: Collapse 增加 TitleColor 参数
* style: 更新 CollapseItem Title 样式
2021-04-14 15:49:42 +08:00
Argo
2761d641d0 !1312 fix(#I3IR9J): Button support change the Icon parameter dynamic
* fix: Icon 支持动态更新
2021-04-14 14:36:27 +08:00
Argo-Cloud
39bf5c595b release: publish 5.0.26-beta07 2021-04-14 11:20:00 +08:00
Argo
c00fab53d4 !1311 feat(#I3IQ1A): MultiSelect support reset SelectedItems after call SetItems method
* docs: 更新 MultiSelect 组件更新数据源重置候选项示例
* feat: MultiSelect 组件切换数据源时支持已选项
2021-04-14 11:12:01 +08:00
Argo
4b24062b44 !1310 feat(#I3IOAD): Avatar component support change GetUrlAsync callback
* fix: 修复 Avatar 组件在表格中无法更新问题
2021-04-14 00:41:00 +08:00
Argo
72b491488e !1309 fix(#I3ILGW): PopoverConfirm button not work with DialogService
* release: publish 5.0.26-beta06
* fix: 修复 Table 组件行内删除按钮不选中行问题
* refactor: 移动 Show 方法到按钮类中
* refactor: 移除对 IsAsync 的支持直接使用 OnClick
* docs: 更新文档
* refactor: 移除 Hide 方法
* Revert "refactor: 删除不使用的文件"
* refactor: 精简服务类内部代码
* refactor: 使用 OnClickButton 优化性能
* refactor: 移除 PopoverConfirmBase 基类
* docs: 更新注释文档
* refactor: 删除不使用的文件
2021-04-13 22:58:46 +08:00
Argo
e20fbd193f !1307 feat(#I3ILXS): add generic method ToEnumDisplayName<TEnum> for EnumExtensions
* feat: 增加 ToEnumDisplayName 泛型方法
* refactor: 增加 Enum 泛型方法
2021-04-13 16:08:45 +08:00
Argo
2b55cbb8ed !1306 docs(#I3IK0J): update Labels sample code link
* docs: 更改 BB 仓库分支为 main
* docs: 增加 ConfigureAwait 方法
* test: 增加一个 delegate 单元测试
* docs: 更改 Labels 位置
2021-04-13 15:53:50 +08:00
Argo
12ba06f35c !1305 refactor(#I3IGXO): RequiredValidator redesign make sure Localizer avaliable
* refactor: RequiredValidator 内部资源文件处理更新
2021-04-12 22:22:15 +08:00
Argo
b8ff10d26b !1304 fix(#I3IGA9): TitleService throw exception object disposed
* refactor: 重构 Title 组件内部逻辑
2021-04-12 18:55:01 +08:00
Argo-Cloud
2edcc489ca release: publish 5.0.26-beta05 2021-04-12 18:27:08 +08:00
Argo
0bb2ae50a4 !1303 fix(#I3IG3A): Layout throw exception when call DisposeAsync
* fix: Layout 组件 DisposeAsync 抛出异常
2021-04-12 18:22:12 +08:00
Argo
ec234e8d3c !1302 docs(#I3IFZU): update README.md file
* docs: 更改 BootstrapBlazor 分支为 main
2021-04-12 18:11:57 +08:00
Argo
99a501d5d2 !1301 chore(#I3ICOP): upgrade sdk to 5.0202
* refactor: 更新依赖组件到 5.05
2021-04-12 13:12:15 +08:00
Argo-Cloud
1af4e6308c release: publish 5.0.26-beta04 2021-04-11 23:59:39 +08:00
Argo
958a9d6ae0 !1300 feat(#I3IA2H): Table SaveModelAsync method support ShowLoading parameter
* docs: 增加 Loading 示例代码链接
* feat: 增加内部 InternalToggleLoading 方法
* refactor: 增加 ShowLoading 支持
* feat: 增加内部 ToggleLoading 方法
2021-04-11 23:33:07 +08:00
Argo
12b49f6fa5 !1299 fix(#I3IA28): resolve throw invalid exception when reload Table component
* fix: 增加 Disposing 保护
2021-04-11 23:29:05 +08:00
Argo-Cloud
bb054152be release: publish 5.0.26-beta03 2021-04-10 23:49:36 +08:00
Argo
bdadf3a83c !1297 feat(#I3I8CP): Table sort feature support ShowLoading parameter
* feat: 重新设计 ShowLoading 方法
* docs: 更新注释
* refactor: 完善 ShowLoading 逻辑
* refactor: 精简代码
* feat: 精简 Loading 代码
* feat: 精简 Loading 代码
* refactor: 精简 Loading 代码
* feat: 更新 OnSortAsync 代码
* script: 更新脚本
2021-04-10 23:45:06 +08:00
Argo-Cloud
e52a236c26 release: publish 5.0.26-beta02 2021-04-09 16:26:01 +08:00
Argo
4ba98c0471 !1293 feat(#I3I447): page and page items support ShowLoading parameter
* feat: Table 组件翻页方法支持 ShowLoading
* feat: 增加 wasm 模式脚本调用判断
* scripts: 更新脚本
2021-04-09 16:25:25 +08:00
Argo
d7f6ef805a !1292 fix(#I3I3OX): not rerender ui after DELETE file on CardUpload component
* style: 更新 CardUpload 宽度
* fix: 修复 CardUpload 无法删除问题
2021-04-09 15:48:34 +08:00
Argo
d8c9f17321 !1291 feat(#I3I268): EditDialog support Table ShowLoading parameter
* feat: EditDialog 增加遮罩
* docs: 更新菜单状态
* script: 增加 EditDialog 遮罩样式与脚本
* docs: 增加数据加载示例文档
* docs: 增加数据加载菜单
* refactor: 移除双向绑定
2021-04-09 12:36:41 +08:00
Argo
b157b76610 !1290 fix(#I3I010): redesign ShowLoading logic of Table component
* release: 5.0.26-beta01
* feat: 搜索相关按钮支持 ShowLoading 功能
* feat: 删除按钮支持 Loading 功能
* perf: 工具栏按钮使用无刷新方法提高性能
* feat: 编辑按钮对 Loading 支持
* feat: 新建按钮增加对 Loading 支持
* refactor: Table 组件刷新按钮提高性能使用无刷新方法
2021-04-09 01:55:14 +08:00
Argo
918266778a !1289 chore(#I3HZQO): upgrade extensions to 5.0.16
* chore: 依赖扩展组件升级到 5.0.16
* chore: 依赖组件升级到 5.0.16
2021-04-08 21:33:44 +08:00
Argo-Cloud
2cdea01d9e release: publish 5.0.25 2021-04-08 20:36:08 +08:00
Argo
a2947ffd2c !1285 feat(#I3HZA6): add SetItems on MultiSelect component
* docs: MultiSelect 增加级联选择示例
* feat: MultiSelect 增加 SetItems 方法
2021-04-08 19:13:11 +08:00
circlelee1981
252d9a713f !1281 fix(#I3HYGJ): throw exception after callback from webapi if close dialog manual
* update Modal.razor.cs 避免重复关闭
2021-04-08 17:12:52 +08:00
Argo
252187a361 !1283 fix(#I3HYFW): revert !1280 PR for fix can't catch property inherit from parent class
* 修复Lambda 扩展方法无法获取基类属性,添加相应单元测试
2021-04-08 17:10:06 +08:00
Argo-Cloud
8420543845 release: publish 5.0.24 2021-04-08 14:58:20 +08:00
Argo
2dab2c3005 !1280 fix(#I3HWSW): throw exception when use new keyword change property Type in sub class
* docs: 格式化文档
* test: 增加单元测试
* fix: Lambda 扩展方法获取属性方法支持继承类使用 new 关键字更改属性类型
* docs: 更新 Items 注释文档
* chore: 更新依赖组件
2021-04-08 14:44:47 +08:00
Argo
cd4322cc20 !1278 feat(#I3HT3D): Upload component support inside ValidateForm
* style: 更新头像上传框样式
* docs: 增加头像框上传组件在表单中使用示例
* feat: 上传组件支持数据验证
* feat: 表单数据验证逻辑增加对 Upload 组件支持
* refactor: Chart/Markdown 组件继承 IDisposable 接口
* feat: 增加 ValidateFile 方法
* feat: AvatarUpload 支持上传文件改变时立即客户端验证
* feat: InputUpload 支持文件改变时立即进行客户端验证
2021-04-07 19:18:56 +08:00
Argo
6217855c84 !1277 refactor(#I3HSBU): Chart/Markdown implement IDisposable interface
* chore: 更新扩展组件版本
* refactor: IAsyncDisposable 接口更新
* refactor: Chart/Markdown 组件继承 IDisposable 接口
2021-04-07 19:10:59 +08:00
Argo
bfc54e86b2 !1276 feat(#I3HK4J): add IsTree parameter on Table component
* docs: 更新 Table 树形数据文档
* feat: Table 组件树形结构又 IsTree 参数控制
2021-04-07 00:40:32 +08:00
Argo
f06d7feda1 !1272 perf(#I3H1FQ): update component inherits IDisposable or IAsyncDisposable interface
* refactor: BootstrapComponentBase 移除 IDispose 接口
* refactor: QRCode 继承 IDispose 接口
* refactor: Rate 继承 IDispose 接口
* refactor: MultiSelect 继承 IDispose 接口
* refactor: Slider 继承 IDispose 接口
* refactor: Swal 继承 IDispose 接口
* refactor: Title 继承 IDispose 接口
* refactor: TableFilter 继承 IDispose 接口
* refactor: Toast 继承 IDispose 接口
* refactor: Timer 继承 IDispose 接口
* refactor: Modal 继承 IDispose 接口
* refactor: Message 继承 IDispose 接口
* refactor: Editor 继承 IDispose 接口
* refactor: Table 组件按钮继承 IDispose 接口
* refactor: Dialog 继承 IDispose 接口
* refactor: TimePickerCell 继承 IDispose 接口
* refactor: ColorPicker 继承 IDispose 接口
* refactor: Captcha 组件继承 IDisposable 接口
* refactor: Camera 继承 IAsyncDisposable 接口
* refactor: ValidateBase 移除 Dispose 方法
* refactor: BarcodeReader 继承 IAsyncDisposable 接口
* feat: Layout 继承 IAsyncDisposable 接口
* revert: 移除 DEBUG 宏定义
2021-04-06 11:51:13 +08:00
Argo
dc10c2ad2d !1271 feat(#I3GOGP): add Data parameter on Display component
* release: publish 5.0.24-beta06
* docs: 更新 Display 组件示例
* feat: Display 组件增加 Data 参数
* release: publish 5.0.24-beta05
2021-04-06 01:48:19 +08:00
Argo
8d9e4bc00a !1270 refactor(#I3GLM6): update the popconfirm button default value
* docs: 更新确认弹窗示例
* docs: 更新确认弹窗按钮默认值
2021-04-06 00:40:31 +08:00
Argo
aa3de4ee74 !1269 fix(#I3GJ68): update extensions version resolve chart and markdown component throw exception
* fix: 更新依赖组件到 5.0.16-beta01
* refactor: 更新依赖组件到最新版
* release: 扩展组件升级到 5.0.14
* refactor: 更新 WebsiteOpitons 支持本地环境
* revert: 移除 Display 同步格式化回调方法
2021-04-05 23:55:29 +08:00
Argo
0f68ef4022 !1268 feat(#I3FKWM): Display provider FormatterAsync callback
* docs: 更新同步格式化回调委托示例
* feat: Display 组件增加同步格式化字符串回调委托
* docs: 更新异步格式化回调委托示例
* feat: Display 组件支持异步格式化
2021-04-05 15:40:35 +08:00
Argo-Cloud
657ed3cf69 release: publish 5.0.24-beta04 2021-04-05 02:02:12 +08:00
Argo
36fb575512 !1267 refactor(#I3FBXA): remove CultureStorageExtensions class
* docs: 更新文档错别字 Content
* refactor: 移除 CultureStorageExtensions 扩展
2021-04-05 01:55:03 +08:00
Argo
4b6e0edaf5 !1266 refactor(#I3FBU8): remove TItem Item parameter
* refactor: 合并 OnClickWithourRender 回调委托
* refactor: 重构 TableCellButton 精简代码
2021-04-05 01:45:12 +08:00
Argo
6a28892db4 !1265 docs(#I3FA8Y): update popconfirm button in cell sample code
* release: publish 5.0.24-beta03
* docs: 更新表格单元格内显示确认弹窗示例
2021-04-04 23:07:36 +08:00
Argo
d299f8b4cf !1264 fix(#I3F9DM): upload validation always failed
* fix: 修复 Upload 客户端验证失效问题
2021-04-04 21:47:37 +08:00
Argo
e036b4ee7c !1263 feat(#I3F81W): add Display component
* docs: 更新示例文档增加 form-inline 示例
* docs: 更新内联样式下 Display 组件示例
* feat: EditorForm 支持 Display 组件
* style: 更新 EditorForm 内 Display 组件样式
* docs: 更新 EditorForm 示例代码
* docs: 更新 Display 组件示例代码
* feat: Display 组件内置对枚举集合数组处理逻辑
* feat: 增加 DisplayBase 基类
* refactor: 重构代码使用 NullableUnderlyingType 变量
* refactor: 重构代码 FormatValueAsString 使用参数
* feat: TooltipComponentBase 继承 IAsyncDisposable 接口
* feat: 更新 Checkbox 默认颜色
* docs: 更新 Display 组件示例文档
* feat: 增加 Display 组件
* docs: 更新 Inputs 组件文档
* feat: 增加组件统计合计配置功能
* docs: 增加 Display 组件菜单
2021-04-04 19:33:03 +08:00
Argo
ab8b333e14 !1262 feat(#I3F0V9): add GetUrlAsync callback method on Avatar
* docs: 更新 Avatar 异步加载图片示例
* feat: Avatar 支持异步加载图片
2021-04-04 00:29:29 +08:00
Argo
d9bbf0853a !1261 feat(#I3EZMH): Checkbox support Color parameter
* docs: 更新示例代码
* feat: Checkbox 组件增加 Color 颜色设置
2021-04-03 21:29:17 +08:00
Argo
8bf4f7aa8d !1260 feat(#I3EZGY): add IsDiabled on SelectItem
* docs: 增加 Select 选项禁用示例
* feat: 增加禁用项点击事件保护
* style: 增加 IsDisabled 样式
* scripts: 更新脚本增加针对 IsDisabled 选项逻辑
* feat: 增加 IsDisalbed 属性
2021-04-03 21:11:13 +08:00
Argo
9b364ae87d !1259 fix(#I3EY3W): SelectedRows of Table always null if not use bind-SelectedRows
* release: publish 5.0.24-beta02
* fix: 修复 SelectedRows 为空
2021-04-03 18:17:52 +08:00
Argo
3e2e6e0198 !1258 feat(#I3EX6X): add Title component
* docs: 更新网站 Title 示例
* docs: 更新首页网站标题
* refactor: 增加资源文件
* feat: 增加 IDisposable 接口逻辑
* docs: 更新 Title 组件文档
* Merge branch 'dev' into dev-title
* docs: 增加网站标题示例文档
* feat: 增加 Title 服务
* scripts: 增加 SetTitle 脚本
2021-04-03 18:01:41 +08:00
Argo
e4a3a886c7 !1257 fix(#I3EVJM): resolve throw exception when change page has Dialog component
* fix: 修复切换页面导致脚本错误问题
* Merge branch 'dev' into dev-toast
* Merge branch 'dev-dialog2' into dev-toast
* Merge branch 'dev-dialog' into dev-toast
* docs: 格式化文档
* docs: 更新 Toasts 文档
* fix: 修复 Modal 组件未释放资源问题
* refactor: SweetAlert 继承 IDispose 接口
2021-04-03 15:45:51 +08:00
Yinmany
c51c2b67e9 !1256 fix(#I3EVJM): Modal should be call dispose method
* update src/BootstrapBlazor/Components/Modal/Modal.razor.cs.
2021-04-03 14:31:46 +08:00
Argo
743ae67586 !1255 feat(#I3EVG0): update DefaultFileList parameter logic in Upload
* refactor: 重构代码
* refactor: 更改 DefaultFileList 逻辑首次加载时读取
2021-04-03 10:57:06 +08:00
Argo
10105843ef !1254 revert(#I3EVFW): revert Avatar logic
* fix: 修复示例文档 Icon 模式未设置图标问题
2021-04-03 10:54:36 +08:00
Argo
de240b9d1c !1253 fix(#I3EVFA): update InputNumber throw exception on ShowButton mode
* fix: 修复 InputNumber 显示按钮时 float double decimal 报错问题
2021-04-03 10:47:07 +08:00
Argo
7ac372fbc5 !1251 fix(#I3EPOP): step attribute missing on Input type is number
* release: publish 5.0.24-beta01
* fix: 修复 Step 生成不正确问题
2021-04-02 02:38:20 +08:00
Argo
6fa9cd4916 !1250 feat(#I3EPO5): add global config for Toast placement
* feat: 全局配置增加 ToastPlacement 设置项
* feat: 增加泛型 Copy 方法
2021-04-02 01:58:01 +08:00
Argo
0d2d01e4d2 !1249 fix(#I3EPN1): column show/hide feature not work on Table card view mode
Merge pull request !1249 from Argo/dev-chore
2021-04-02 00:53:28 +08:00
circlelee1981
48cfc05834 !1247 SearchText lambda expression should be use Or logic
* update DefaultDataService 参与搜索的各条件用"OR"运算
2021-04-02 00:26:47 +08:00
Argo
07c9da99e1 !1248 feat(#I3EGFT): TimePicker can use mouse wheel choose time
* refactor: 兼容 firefox
* feat: 增加滚轮逻辑代码
* refactor: 增加 Interop 类带返回值方法
* script: 增加滚轮 js 效果代码
2021-04-02 00:18:43 +08:00
Argo
3fc6c80c86 !1245 chore(#I3EM8C): update dependence to 5.0.23
* chore: 更新扩展组件版本
* chore: 扩展类版本更新到 5.0.13
* refactor: 移除 Markdown 版本号
2021-04-01 16:00:22 +08:00
Argo-Cloud
f8dcc0b6b2 release: publish 5.0.23 2021-04-01 13:47:35 +08:00
Argo
73a34d169d !1244 docs(#I3EJIM): update selected rows in line Button sample code
* docs: 更新行内按钮操作后选中当前行示例
* feat: 行内按钮支持设置当前行选中功能
* fix: 修复小屏幕下行号不正确问题
2021-04-01 12:08:54 +08:00
Argo
bdda880aa5 !1243 fix(#I3EJHX): table line no keep increase on mobile mode
* fix: 修复小屏幕下行号不正确问题
2021-04-01 12:04:49 +08:00
Argo
62cae7a29e !1242 feat(#I3EIU2): InputNumber set default value for single double decimal
* feat: Step 增加默认值
2021-04-01 11:01:38 +08:00
Argo
abbbfdd0a3 !1241 feat(#I3EHKZ): add checkbox-list style for min-height default value 35px
* style: 更新样式设置最小高度
2021-04-01 00:26:46 +08:00
Argo
c1e6fffdee !1240 refactor(#I3EHK7): redesign EditorForm cascading value for show label
* feat: 修复 EditorForm 级联参数确保 ShowLabel 判断准确
2021-04-01 00:12:32 +08:00
Argo
324455eedd !1239 fix(#I3EGGO): validate component should not auto show label when bind data
* fix: 修复 EditorForm ShowLabel 逻辑
2021-03-31 18:13:54 +08:00
Argo-Cloud
4941e31bb7 release: publish 5.0.23-beta13 2021-03-31 17:40:51 +08:00
Argo
4a15cd7608 !1238 feat(#I3D6UP): update ValidateForm/EditorForm/Validate component ShowLabel logic
* docs: 增加表单标签菜单
* docs: 更新文档
* feat: 调整 CheckboxList 显示内容
* feat: 优先考虑 EditorForm 未嵌套 ValidateForm 情况
* docs: 增加 label 文档
* refactor: 更改方法关键字
* feat: 更新 Checkbox ShowLabel 逻辑
* feat: 更新 ShowLabel 逻辑
* refactor: Toggle 组件使用 IsShowLabel 参数
* refactor: EditForm 更改为 ValidateForm
* feat: ValidateForm 增加 ShowLabel 参数
* feat: EditorForm ShowLabel 参数使用 ValidateForm 级联值
2021-03-31 17:40:16 +08:00
Argo
437b4d96c7 !1237 feat(#I3EG1S): avatar/upload support reset Url parameter use code
* feat: 更改参数逻辑
2021-03-31 17:39:05 +08:00
Argo-Cloud
7d740425e7 release: publish 5.0.23-beta12 2021-03-31 01:27:43 +08:00
Argo
8155325018 !1236 fix(#I3EB63): not restore the default display text when use variable
* fix: 修复标签不能动态改变问题
2021-03-31 01:13:28 +08:00
Argo
3555963903 !1235 docs(#I3EB62): update docs for table edit sample code
* docs: 更新无限弹窗示例
* docs: 增加 TableEdit 示例文档说明
* Merge branch 'dev' into dev-docs
* refactor: remove SetKey
* refactor: update key
* refactor: 优化代码
* docs: update sample code link
2021-03-31 01:04:50 +08:00
Argo
05246ee852 !1234 fix(#I3EB4V): ValidateForm valid failed when change model by code
* fix: 修复 ValidateForm 表单不支持动态更改 Model 问题
2021-03-31 00:18:44 +08:00
zglp
f215ecec7b !1230 docs(#I3E9Q5): update Dialog ShowModal sample code
* 移除多余空格
* Merge remote-tracking branch 'Argo/dev-dialog-table' into dev-DialogShowModal
* Merge branch 'dev' into dev-DialogShowModal
* fix: 修复弹窗实战示例2
* 修复对话框调用ShowModal组件渲染两次
2021-03-30 17:44:54 +08:00
Argo
68283dda24 !1233 docs(#I3E8DI): remove unused c# file
* refactor: 重构代码逻辑
* refactor: 移除文件
* docs: 更新明细行示例代码
2021-03-30 15:52:05 +08:00
Argo
ad35968019 !1231 docs(#I3E7HZ): update Table AufoRefresh sample code
* docs: 更新配置文档
* docs: 更新 Table 组件自动更新文档示例
2021-03-30 14:35:26 +08:00
Argo
3610c1e89f !1229 docs(#I3E6RM): update Table Column sample code
* docs: 更新列示例文档
* chore: update nuget package source
* chore: update eidtorconfig file
2021-03-30 13:03:49 +08:00
Argo-Cloud
a03d6d4869 chore: add nuget.config file 2021-03-29 17:17:19 +08:00
Argo-Cloud
5517556bb9 release: markdown 组件发布 beta01 版本 2021-03-29 16:48:48 +08:00
Argo
37c562d176 !1228 feat(#I3E183): VadliateForm support async submit button
* docs: 增加异步提交表单示例
* feat: 验证表单支持异步提交按钮
2021-03-29 15:29:07 +08:00
j4587698
b27ed69ada !1227 feat(#I3DX9J): add IsViewer for Markdown component
* 添加MarkdownEditor的Viewer模式
2021-03-29 15:23:38 +08:00
Argo
d37f192a66 !1226 feat(#I3DZKZ): add logic for single async button on Table Toolbar
* docs: 更新示例文档
* feat: 增加异步按钮单独控制功能
2021-03-29 12:03:02 +08:00
Argo
ecf6bd1464 !1225 fix(#I3DYX5): select All item in Table filter not trigger OnQueryAsync method
* fix: 修复 Table Filter 功能选择全部时不重新查询问题
2021-03-29 11:04:18 +08:00
Argo
52462a457c !1224 feat(#I3DYJF): add style for label not required in validate form
* style: 微调表单组件内 Label 对齐方式
2021-03-29 10:35:36 +08:00
Argo
c0a19c9596 !1223 fix(#I3DXDI): expand all items when click padding area on Collapse body
* release: publish 5.0.23-beta10
* refactor: 增加静态关键字
* fix: 移除点击事件
2021-03-29 00:23:40 +08:00
Argo
82366af97a !1222 refactor(#I3DWY8): change service lifetime to scope
* refactor: 移除 BootstrapBlazorRoot 代码
* refactor: 重构代码
* feat: 更新 ServiceProviderHelper 逻辑
* refactor: 重构代码
* refactor: 更改服务生命周期为 Scope
2021-03-28 18:58:09 +08:00
Argo
e7c9a879e9 !1221 docs(#I3DWJQ): update async download sample code
* release: publish 5.0.23-beta08
* docs: 更新异步下载示例
2021-03-28 15:14:42 +08:00
Argo
9d316d6abf !1220 feat(#I3DWIV): ToolbarButton support IsAsync mode
* docs: 更新异步下载示例
* feat: TableToolbarButton 支持 IsAsync 功能
* docs: 更新 Table 组件数据导出示例
* feat: 更改 ToastBox 参数形式
* feat: ToastOption 配置类内置 ToastBox 实例用于关闭弹窗
* refactor: 精简代码
* scripts: 增加关闭弹窗方法
* docs: 增加异步下载示例
* docs: 更新注释文档
2021-03-28 15:07:28 +08:00
Argo
8614831edc !1219 feat(#I3DWIO): add Close method on ToastOption
* docs: 更新 Table 组件数据导出示例
* feat: 更改 ToastBox 参数形式
* feat: ToastOption 配置类内置 ToastBox 实例用于关闭弹窗
* refactor: 精简代码
* scripts: 增加关闭弹窗方法
* docs: 更新注释文档
2021-03-28 15:05:36 +08:00
Argo
3fbf39878a !1218 fix(#I3DVN9): filter the Editable property on EditDialog if not set Items value
* Merge branch 'dev' into dev-editor-dialog
* release: publish 5.0.23-beta07
* fix: EditDialog 自动使用 Editable 条件的属性
* refactor: 更改参数类型为 KeyValuePair<string, object?>
2021-03-28 02:15:46 +08:00
Argo
74e4268f01 !1217 refactor(#I3DVN8): use KeyValuePair<string, object?> type for NET6.0
* refactor: 更改参数类型为 KeyValuePair<string, object?>
2021-03-28 02:08:42 +08:00
Argo
e592416919 !1216 fix(#I3DVN3): not filter the Searchable condition in SearchDialog
* fix: SearchDialog 未过滤 Searchable 条件
* refactor: 更新 GenerateColumns 方法
2021-03-28 01:40:48 +08:00
Argo
b525035da4 !1215 fix(#I3DVN2): update Button logic prevent reassign OnClick event callback
* fix: 修复 Button 点击事件二次赋值问题
2021-03-28 01:38:25 +08:00
Argo
ec3a123bfb !1214 feat(#I3DVAK): add IsAsync parameter on Button
* docs: 更新按钮菜单状态
* docs: 增加异步加载示例
* feat: Button 增加 IsAsync 属性
* refactor: 移除不使用的代码
2021-03-27 20:17:39 +08:00
Argo
5f121ec1ce !1213 fix(#I3DUHU): duplicate add Button in table toolbar when switch ShowButton
* release: pubulish 5.0.23-beta06
* fix: 修复按钮添加后无法移除问题
2021-03-27 14:53:50 +08:00
Argo
fbe7fd228b !1212 docs(#I3DU7B): add row menu link
* refactor: 移除测试按钮
* docs: add row component menu
* docs: update checkboxlist IsDisabled doc
* docs: 增加 ValidateForm 视频链接
2021-03-27 13:30:03 +08:00
Argo
72420740ea !1211 feat(#I3DU67): upload support Disable feature
* feat: 卡片式上传组件支持禁用
* style: 更新卡片式上传组件样式
* feat: 头像上传组件支持禁用
* style: 头像类型上传组件更新样式
* feat: 上传按钮样式组件支持禁用
* style: 更新样式
* refactor: InputUpload 增加禁用功能
2021-03-27 12:59:36 +08:00
Argo
11dace83c6 !1210 docs(#I3DTRQ): add DataService sample code
* docs: 增加自定义数据服务示例
2021-03-27 10:46:19 +08:00
Argo
82ca776f88 !1209 feat(#I3DTRL): add disable feature on CheckboxList
* docs: CheckboxList 增加禁用示例
* feat: CheckboxList 支持禁用功能
2021-03-27 10:44:50 +08:00
Argo
978279f363 !1208 fix(#I3DP5D): remove editable is false items in Table use EditMode is EditForm
* release: publish 5.0.23-beta05
* fix: 修复 EditMode 为 EditForm 时自动生成 Editable = false 列仍然出现
2021-03-26 21:10:13 +08:00
Argo
18b1c3bf86 !1207 refactor(#I3DP46): remove BootstrapBlazorRoot component
* release: publish 5.0.23-beta04
* feat: 完善 ServiceProviderHelper 逻辑
2021-03-26 20:55:53 +08:00
Argo
e5cf86ea4f !1206 feat(#I3DN0R): redesign Upload component for inside in ValidateForm
* release: publish 5.0.23-beta03
* docs: 更新资源文件
* docs: 更新设置预览地址示例
* docs: 更新示例文档
* feat: 增加表单内使用显示标签方法
* refactor: 增加泛型支持
2021-03-26 17:30:39 +08:00
Argo
c162fc28e5 !1205 docs(#I3DKZQ): add Bulma link
* docs: 增加 Bulma 链接
2021-03-26 15:55:30 +08:00
Argo
5ea38c99d1 !1204 fix(#I3DHAR): improve ServiceProviderHelper class use BootstrapBlazorRoot make sure use the same ServiceProvider
* docs: 格式化 wasm 代码
* refactor: 精简代码移除注册服务代码
* docs: 示例文档增加 BootstrapBlazorRoot 组件
* feat: 增加 BootstrapBlazorRoot 组件
* refactor: 更改注入服务生命周期为 Singleton
* docs: 更改 SwalService 注入服务位置
* docs: 增加主题切换配置
* docs: 更新 Theme 主题切换按钮 z-index = 10
2021-03-26 15:04:25 +08:00
Argo
ca286e8e99 !1203 feat(#I3DF9O): add ShowResetSearch parameter default value is true
* docs: 更新清空搜索按钮文档
* feat: 增加清空搜索按钮控制参数
2021-03-26 00:18:17 +08:00
Argo
131473a5c0 !1202 docs(#I3DECD): update table export sample code
* docs: 更新导出示例链接
* docs: 更新导出功能示例
2021-03-25 23:21:46 +08:00
Argo
eb992f8ada !1201 docs(#I3DDGK): update table filter sample code
* docs: 更新示例文档链接
* docs: 更新过滤示例代码
2021-03-25 22:23:30 +08:00
Argo-Cloud
c04a142697 release: publish 5.0.23-beta01 2021-03-25 22:44:02 +08:00
zglp
120c22ccb3 !1198 fix(#I3DC8H): missing ValidateContext in CustomerValidator
* 修复自定义ValidationAttribute时ValidationContext为null
2021-03-25 20:43:18 +08:00
Argo
6cd9acf32d !1200 feat(#I3D7YR): add red * before label when bind field has required attribute
* feat: 增加 Required 标签检查
* docs: 更新文档
* style: 更新样式
* feat: 表单组件支持必填项显示 *
* feat: VaildateBase 增加 Required 属性用于增加 html 标签
* feat: ValidateForm 增加 ShowRequiredMark 参数默认为 true
* refactor: 使用注入服务获取 JsonLocalzationOptions
2021-03-25 18:32:01 +08:00
Argo
f722ad07fe !1199 feat(#I3D71B): update ServiceProviderHelper logic for make ServiceProvider same scope
* refactor: 根据 ServiceProviderHelper 调整代码
* feat: 增加 ssr 模式对 HttpContextAccessor 的注入
* feat: 更新 ServiceProviderHelper 内部逻辑保证 Scope 一致性
2021-03-25 15:31:20 +08:00
Argo
de747e1bc2 !1197 feat(#I3CXJY): Select auto generate Items if TValue is enum
* docs: 精简代码不需要设置 Items
* docs: 更新 ValidateForms 中对 Select 枚举类型处理示例
* feat: Select 组件内置对枚举类型的处理
* docs: 更新 ValidateForm 示例文档
* refactor: 更新 SetError 方法
2021-03-24 16:04:34 +08:00
zglp
d05b6bba8c !1195 fix(#I3CTEJ): update OnTreeExpand method
* 修复OnTreeExpand中调用异步函数出错
2021-03-24 11:36:04 +08:00
Argo
a28667f25e !1196 docs(#I3CSYA): update dependence lib
* chore: 更新依赖组件到最新版
* chore: 扩展类更新版本懂啊 5.0.12
2021-03-24 11:23:29 +08:00
刘亮
23e385b107 !1194 feat(#I3CSX1): add SetError override method
* 加入SetError的一个重载,使用字符串指定字段
2021-03-24 11:16:51 +08:00
Argo Zhang
c50d429102 docs: add link for changelog 5.0.22 2021-03-24 10:37:31 +08:00
Argo Zhang
a9ccb16e19 release: publish 5.0.22 2021-03-24 10:28:15 +08:00
Argo Zhang
49ecc6cc27 docs: update changelog 5.0.22 2021-03-24 10:22:57 +08:00
Argo-Cloud
e24d35e3b7 release: publish 5.0.22-beta04 2021-03-24 03:02:18 +08:00
Argo
6c6af4a444 !1193 feat(#I3CQYI): add OnEditAsync callback on Table
* feat: 增加 OnEditAsync 回调委托
2021-03-24 00:54:53 +08:00
Argo
e84bbc3e4d !1192 feat(#I3CQY7): redesign row component for grid layout
* docs: 微调文档
* chore: 开启压缩
* Merge branch 'dev' into dev-rows
* docs: 更新示例代码
* scripts: 支持嵌套使用
* Merge branch 'dev' into dev-rows
* feat: IValidateComponent 增加禁用与跳过属性
* docs: 更新示例代码
* refactor: 精简代码
* feat: 增加 grid 脚本用于自动布局
* docs: 更新嵌套示例
* docs: 更新 Row 组件示例使用实际组件呈现
* style: 更新 Select 在 Row 组件中的布局样式
* style: 增加 Switch 组件在 form-row 中的布局样式
* docs: 更新示例
* feat: 完善布局脚本
* docs: 更新示例
* chore: 增加样式与脚本
* refactor: 更新 Row 组件
* feat: 增加 row 类型与每行组件数量枚举类型
* revert: 重置 BootstrapComponentBase
2021-03-24 00:37:10 +08:00
Argo
4b5524c583 !1191 feat(#I3CQXQ): auto generate column can customer component for property
* Merge branch 'dev' into dev-EditorForm
* docs: 移除布尔类型数据渲染模板
* feat: 组件内部处理 bool 数据类型呈现组件
* feat: IEditorItem 增加 ComponentType 属性可自定义呈现组件
2021-03-24 00:19:29 +08:00
Argo
8caca1b0e5 !1190 docs(#I3CQXN): update table detail row sample code
* docs: 更新明细行示例
2021-03-24 00:13:05 +08:00
Argo
fa56698d87 !1189 fix(#I3CPLZ): update item count in EFCore data service
* release: 发布 5.0.12-beta02
* fix: 修复 EFCore 页码不正确问题
2021-03-23 18:42:01 +08:00
Argo
3b24f9ccc7 !1188 feat(#I3CPJK): Switch compatible with Row
* style: 增加 Switch 组件在 form-row 中的布局样式
2021-03-23 18:30:03 +08:00
Argo
6d35296b37 !1187 feat(#I3CPJ8): Select compatible with Row
* style: 更新 Select 在 Row 组件中的布局样式
2021-03-23 18:26:57 +08:00
Argo
ca6ece9ac8 !1186 perf(#I3CPID): improve validate performance
* feat: IValidateComponent 增加禁用与跳过属性
2021-03-23 18:23:02 +08:00
zglp
7f78203481 !1172 feat(#I3CFJS): keep Tree expand state after edit
* 修复编辑后Table树形结构自动收缩的问题
* 添加具有单表维护功能的树形数据案例
* 修复Table树形结构数据源不更新问题
2021-03-22 14:07:30 +08:00
Argo
14668753de !1185 fix(#I3CFAS): update logic in EFCore extensions
* fix: 修复默认条件导致递归无限循环问题
* fix: 修复 EFCore 扩展导致高级搜索高亮问题
* fix: 修复 EFCore 扩展过滤条件缺失 Filter 判断问题
2021-03-22 13:43:33 +08:00
circlelee1981
4aec42a6ae !1181 fix(#I3CFAS): remove condition default parameter
* update IQueryableExtensions.cs 去除condition参数的默认值, 避免递归运算
2021-03-22 13:41:30 +08:00
Argo
1d106f0261 !1184 docs(#I3CF7E): update Foo sample code
* refactor: 拆分 Educations 到 Rows 组件内部
2021-03-22 13:28:18 +08:00
Argo
4cb72b5584 !1183 fix(#I3CF4K): use same service lifetime in EFCore extensions
* release: 发布 5.0.12-beta01
* fix: 修复注册服务生命周期不一致问题
2021-03-22 13:25:54 +08:00
Argo
09b750b57f !1182 docs(#I3CF12): update fixed column sample code
* docs: 更新固定列示例代码
* docs: 格式化文档
* docs: update components (#74)
2021-03-22 12:37:59 +08:00
Argo
10b205b67d !1178 fix(#I3CCK1): update SwalService for Delay parameter use WebSiteOption config
* fix: 修复 Swal 组件延时时间未使用全局配置问题
2021-03-21 21:59:13 +08:00
Argo
288e32da5e !1177 fix(#I3CCIQ): update Message for effect of WebsiteOption MessageDelay config
* feat: Message 组件支持全局配置延时时间
* refactor: 移除 MessageBase 基类
2021-03-21 21:43:32 +08:00
Argo
2b429cb9e0 !1176 docs(#I3CC5Q): update target framework config
* docs: 更新 Table 树形数据视频链接
* chore: 更改目标框架设置文件
* release: publish 5.022-beta03
* chore: 更新框架版本脚本
2021-03-21 17:57:01 +08:00
Argo
5f9d9388a8 !1175 fix(#I3CBSW): use ManualEventReset compatible with web assembly
* refactor: 修复 wasm 版本号无法使用 FileVersionInfo 类问题
* refactor: 移除 ManualResetEventSlim 类修复 wasm 无法使用问题
2021-03-21 14:57:27 +08:00
Argo
29bbffe68e !1174 chore(#I3CBS1): use props file set TargetFramework
* chore: 统一设置框架
* chore: net5.0 框架消除 8620 警告
* refactor: 重构参数集合可为空消除警告
2021-03-21 14:50:57 +08:00
Argo
217cc078ca !1173 feat(#I3CBQT): wasm add check browser compatibility
* feat: 增加不支持 wasm 检测
2021-03-21 14:29:47 +08:00
Argo
d6b05efc5d !1171 feat(#I3CBI6): add complex poco data annotation validation
* release: publish 5.0.22-beta02
* docs: 更新 SetError 示例
* feat: 更新 SetError 方法
* feat: 更新 ValidateContext DisplayName
* docs: 更新资源文件
* docs: 增加复杂类型数据验证支持
* docs: 增加资源文件
* feat: ValidateForm 支持验证所有字段
* feat: 重新设计验证逻辑支持复杂类型
* feat: Lambda 扩展方法增加 GetPropertyValue 方法
* feat: Validate 组件 id 生成规则增加 Model 值
* refactor: 增加级联参数判断
2021-03-21 11:31:03 +08:00
Argo
dfbc622273 !1170 refactor(#I3CA0I): rename DynamicComponent to BootstrapDynamicComponent
* docs: 更新文档链接
* refactor: DynamicComponent 改名为 BootstraplDynamicComponent
* feat: 增加 BootstrapDynamicComponent 类
2021-03-20 15:08:21 +08:00
Argo
33557825cf !1169 docs(#I3C8Q3): update dialog samples
* docs: update dialog samples
* docs: 更新无限弹窗示例
* feat: 移除 KeepChildrenState 参数
* fix: 修复 Tab 组件在弹窗中 active 蓝条初始化不正确问题
2021-03-20 00:29:53 +08:00
Argo
ee21d06ffa !1168 fix(#I3C8PH): update Tab miss under line style in Dialog when first render
* fix: 修复 Tab 组件在弹窗中 active 蓝条初始化不正确问题
2021-03-20 00:15:21 +08:00
Argo-Cloud
9088449686 release: publish 5.0.22-beta01 2021-03-19 15:42:06 +08:00
Argo
d44a8a59b8 !1167 feat(#I3C6GH): add loading icon for delay load tree children data on Table
* docs: 更新示例代码增加 1 秒延时示例
* feat: 增加属性数据节点展开动画效果
* style: 移除树形数据节点样式
2021-03-19 15:41:30 +08:00
Argo
fefaa2ba00 !1166 docs(#I3C4HV): update fix header sample code
* docs: 更新固定表头示例
2021-03-19 11:29:42 +08:00
Argo
175cd55b8b !1165 docs(#I3C4F0): update multiple table header sample
* docs: Table 组件更新多表头示例
2021-03-19 11:21:50 +08:00
Argo
3b0314026b !1164 fix(#I3C436): update row logic
Merge pull request !1164 from Argo/dev-rows
2021-03-19 10:47:07 +08:00
liu liang
7053d7345d feat: update row logic
(cherry picked from commit e72baf078b757a761b5cb1765033e7876c71a674)
2021-03-19 10:44:27 +08:00
Argo
1bb9c2aa51 !1163 fix(#I3C2W4): advance search button highlight when use NullDataService
* fix: 修复内置数据注入服务导致高级搜索高亮
2021-03-19 00:17:19 +08:00
Argo
9b39bbcb5e !1162 docs(#I3C2W1): add changelog markdown file
* docs: 增加 changelog 文档
* docs: 更新 Readme 文档增加小挂件
2021-03-19 00:14:38 +08:00
Argo
98d00a409e !1161 fix(#I3C205): move switch click handler to span element
* fix: 移动 onclick 事件到 span 元素上
* refactor: 移除自定义显示文本
* style: 微调小屏幕下 Table 组件的值列高度问题
* style: 微调 switch 组件在表单内的高度
* refactor: 移除 SwitchBase 基类
2021-03-18 19:24:23 +08:00
Argo-Cloud
f08b573e8f chore: update dependeces version to 5.0.11 2021-03-18 16:48:41 +08:00
Argo-Cloud
9bb79547e2 chore: upgrade extension version to 5.0.11 2021-03-18 16:41:38 +08:00
411 changed files with 11090 additions and 5142 deletions

View File

@@ -64,8 +64,8 @@ dotnet_style_explicit_tuple_names = true:suggestion
dotnet_style_null_propagation = true:suggestion
dotnet_style_coalesce_expression = true:suggestion
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent
dotnet_prefer_inferred_tuple_names = true:suggestion
dotnet_prefer_inferred_anonymous_type_member_names = true:suggestion
dotnet_style_prefer_inferred_tuple_names = true:suggestion
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
dotnet_style_prefer_auto_properties = true:silent
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
dotnet_style_prefer_conditional_expression_over_return = true:silent

26
.github/workflows/build.yml vendored Normal file
View File

@@ -0,0 +1,26 @@
name: Build Project
on:
push:
branches:
- main
- dev
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup .NET Core
uses: actions/setup-dotnet@v1
with:
dotnet-version: 5.0.202
- name: Build
env:
NUGET_API_KEY: ${{secrets.NUGET_API_KEY}}
run: |
dotnet restore src/BootstrapBlazor --no-cache
dotnet build src/BootstrapBlazor

View File

@@ -15,7 +15,7 @@ jobs:
- name: Setup .NET Core
uses: actions/setup-dotnet@v1
with:
dotnet-version: 5.0.201
dotnet-version: 5.0.202
- name: Publish to Nuget
env:

View File

@@ -15,7 +15,7 @@ jobs:
- name: Setup .NET Core
uses: actions/setup-dotnet@v1
with:
dotnet-version: 5.0.201
dotnet-version: 5.0.202
- name: Publish wasm
run: |

View File

@@ -15,7 +15,7 @@ jobs:
- name: Setup .NET Core
uses: actions/setup-dotnet@v1
with:
dotnet-version: 5.0.201
dotnet-version: 5.0.202
- name: Publish to Nuget
env:

View File

@@ -36,6 +36,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "appveyor", "appveyor", "{1E
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "github", "github", "{F0754254-903C-411B-972C-EC91254B4A67}"
ProjectSection(SolutionItems) = preProject
.github\workflows\build.yml = .github\workflows\build.yml
.github\workflows\deploy.yml = .github\workflows\deploy.yml
.github\workflows\pack.yml = .github\workflows\pack.yml
.github\workflows\publish.yml = .github\workflows\publish.yml
@@ -65,9 +66,6 @@ EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTest", "test\UnitTest\UnitTest.csproj", "{190F25CF-C6F9-4964-97E9-F6A912D527AE}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "extensions", "extensions", "{22328011-53B3-447A-B781-AC3C196B2847}"
ProjectSection(SolutionItems) = preProject
src\Extensions\Directory.Build.props = src\Extensions\Directory.Build.props
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "wasm", "wasm", "{C8E79F4C-8C55-4E13-96B5-3D2BD6A07B74}"
EndProject

90
CHANGELOG.zh-CN.md Normal file
View File

@@ -0,0 +1,90 @@
<h1 align="center">Bootstrap Blazor 组件库</h1>
<div align="center">
<h2>一套基于 Bootstrap 和 Blazor 的企业级组件库</h2>
[![Nuget](https://img.shields.io/nuget/v/BootstrapBlazor.svg?color=red&logo=nuget&logoColor=green)](https://www.nuget.org/packages/BootstrapBlazor/)
[![Nuget](https://img.shields.io/nuget/dt/BootstrapBlazor.svg?logo=nuget&logoColor=green)](https://www.nuget.org/packages/BootstrapBlazor/)
[![Commit Date](https://img.shields.io/github/last-commit/ArgoZhang/BootstrapBlazor/master.svg?logo=github&logoColor=green&label=commit)](https://github.com/ArgoZhang/BootstrapBlazor)
</div>
---
### 发布周期
- 主版本号:与 Microsoft .NET 主版本号一致
- 次版本号:与 Microsoft .NET 次版本号一致
- 修订版本号:每周四发布正式版(翻车紧急修复会跳版本号)日常每天发布新功能测试版本或者修复 BUG 测试版本 beta-##
---
### 5.0.22
`2021-03-24`
#### 增加功能
- !1193 feat(#I3CQYI): Table 组件编辑按钮增加回调委托 [#I3CQYI](https://gitee.com/LongbowEnterprise/BootstrapBlazor/pulls/1193)
- !1192 feat(#I3CQY7): 增加 Row 组件用于栅格系统布局 [#I3CQY7](https://gitee.com/LongbowEnterprise/BootstrapBlazor/pulls/1192)
- !1191 feat(#I3CQXQ): 自动生成标签 AutoGenerateColumn 增加 ComponentType 属性用于自定义呈现组件 [#I3CQXQ](https://gitee.com/LongbowEnterprise/BootstrapBlazor/pulls/1191)
- !1188 feat(#I3CQY7): Switch 组件适配 Row 组件支持 row form-row form-inline 三种模式 [#I3CQY7](https://gitee.com/LongbowEnterprise/BootstrapBlazor/pulls/1188)
- !1187 feat(#I3CPJ8): Select 组件适配 Row 组件支持 row form-row form-inline 三种模式 [#I3CPJ8](https://gitee.com/LongbowEnterprise/BootstrapBlazor/pulls/1187)
- !1172 feat(#I3CFJS): Table 组件树形数据支持 CRUD 并且保持编辑前展开收缩状态 [#I3CFJS](https://gitee.com/LongbowEnterprise/BootstrapBlazor/pulls/1172)
- !1173 feat(#I3CBQT): 增加演示网站 wasm 模式对浏览器是否兼容性提示功能 [#I3CBQT](https://gitee.com/LongbowEnterprise/BootstrapBlazor/pulls/1173)
- !1171 feat(#I3CBI6): DataAnnotation 支持复杂类型的验证 [#I3CBI6](https://gitee.com/LongbowEnterprise/BootstrapBlazor/pulls/1171)
- !1167 feat(#I3C6GH): Table 组件展开树形数据是增加 Spin 动画效果 [#I3C6GH](https://gitee.com/LongbowEnterprise/BootstrapBlazor/pulls/1167)
#### 问题修复
- !1189 fix(#I3CPLZ): 更新 EFCore 数据注入服务获取记录总数逻辑 [#I3CPLZ](https://gitee.com/LongbowEnterprise/BootstrapBlazor/pulls/1189)
- !1185 fix(#I3CFAS): 修复 EFCore 数据注入服务排序导致递归循环引用问题 [#I3CFAS](https://gitee.com/LongbowEnterprise/BootstrapBlazor/pulls/1185)
- !1183 fix(#I3CF4K): 更新 EFCore 数据注入服务使服务生命周期内部与参数一致默认 Scope [#I3CF4K](https://gitee.com/LongbowEnterprise/BootstrapBlazor/pulls/1183)
- !1178 fix(#I3CCK1): 修复全局配置 SwalDelay 参数在 Swal 组件中未生效问题 [#I3CCK1](https://gitee.com/LongbowEnterprise/BootstrapBlazor/pulls/1178)
- !1177 fix(#I3CCIQ): 修复全局配置 MessageDelay 参数在 Message 组件中未生效问题 [#I3CCIQ](https://gitee.com/LongbowEnterprise/BootstrapBlazor/pulls/1177)
- !1175 fix(#I3CBSW): 修复 Timer 计时器组件不兼容 wasm 模式问题 [#I3CBSW](https://gitee.com/LongbowEnterprise/BootstrapBlazor/pulls/1175)
- !1168 fix(#I3C8PH): 修复 Tab 组件首次加载时活动标签页蓝色火柴棍特效不能正常呈现问题 [#I3C8PH](https://gitee.com/LongbowEnterprise/BootstrapBlazor/pulls/1168)
- !1163 fix(#I3C2W4): 修复内置数据服务导致高级搜索默认高亮状态问题 [#I3C2W4](https://gitee.com/LongbowEnterprise/BootstrapBlazor/pulls/1163)
- !1161 fix(#I3C205): 更新 Switch 组件点击事件触发组件 [#I3C205](https://gitee.com/LongbowEnterprise/BootstrapBlazor/pulls/1161)
#### 示例更新
- !1190 docs(#I3CQXN): 更新 Table 组件明细行示例代码
- !1182 docs(#I3CF12): 更新 Table 组件更新固定列示例代码
- !1169 docs(#I3C8Q3): 更新 dialog 示例代码
- !1166 docs(#I3C4HV): 更新 Table 组件固定表头示例代码
- !1165 docs(#I3C4F0): 更新 Table 组件多表头示例代码
#### 性能优化
- !1186 perf(#I3CPID): 优化 ValidateForm 组件提高内部性能 [#I3CPID](https://gitee.com/LongbowEnterprise/BootstrapBlazor/pulls/1186)
- !1170 refactor(#I3CA0I): DynamicComponent 改名为 BootstrapDynamicComponent [#I3CA0I](https://gitee.com/LongbowEnterprise/BootstrapBlazor/pulls/1170)
### 5.0.21
`2021-03-18`
* !1158 feat(#I3BULP): Table 组件增加数据服参数未设置时使用全局注入数据服务
* !1157 feat(#I3BUL0): MultiSelect 组件支持双向绑定数组类型
* !1155 feat(#I3BNXX): ValidateForm 组件增加 ValidateAllProperties 参数是否开启检查所有字段默认 false 仅检查表单中的绑定字段
* !1154 feat(#I3BN0L): ValidateForm 组件增加 SetError 方法可主动设置绑定字段提示信息
* !1153 feat(#I3BKXC): 优化 Upload 组件 ButtonUpload 模式上传失败后鼠标悬停图标
* !1152 fix(#I3ALSP): 修复 Upload 组件 ShowProgress 与 IsMultiple 参数共同使用时出错问题
* !1151 fix(#I3BGMV): 修复 Table 组件固定列后选中行样式被遮挡问题
* !1147 fix(#I3AB7H): Upload 组件上传中增加 Spin 动画
* !1145 fix(#I3BEBQ): 修复 Cascader 组件选中项样式
* !1144 fix(#I3BBNS): 修复 Table 组件加载树形数据后与 ClickToSelect 参数冲突问题
* !1143 perf(#I3BBMK): 优化 SweetAlert 组件内部弹窗性能
* !1142 feat(#I3BADG): Dialog 组件支持无限弹窗
* !1140 fix(#I3B9GU): 修复 Cascader 组件选择后显示文字不更新问题
* !1139 feat(#I3B8RN): 演示站点增加切换主题功能
* !1138 feat(#I3B8FX): Table 组件增加 ShowErrorToast 参数用于控制是否显示操作提示弹窗
* !1137 feat(#I3B7UV): 新增 Cascader 组件
* !1136 fix(#I3B502): 修复 Table 组件 ClickToSelect 属性与扩展操作按钮冲突问题
* !1134 fix(#I3B50S): 修复 Table 组件树形数据点击节点无刷新问题
* !1131 docs(#I3B1VU): Table 组件更新分页示例
* !1130 feat(#I3B1VL): EditorForm 组件自动布局支持 Textarea 组件类型
* !1128 fix(#I3AZOI): 修复 Menu 组件顶栏超过 5 个子菜单时样式不正确问题
* !1127 perf(#I3AYCH): 优化 Dialog 组件性能阻止点击关闭等按钮导致子组件二次渲染问题

View File

@@ -1,5 +1,6 @@
<Project>
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<Copyright>Argo Zhang</Copyright>
<Authors>Argo Zhang(argo@163.com)</Authors>
<Company>Longbow</Company>

8
NuGet.Config Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="azure" value="https://nuget.cdn.azure.cn/v3/index.json" />
<add key="cnblogs" value="https://nuget.cnblogs.com/v3/index.json" />
<add key="huawei" value="https://repo.huaweicloud.com/repository/nuget/v3/index.json" />
</packageSources>
</configuration>

View File

@@ -1,15 +1,15 @@
<h1 align="center">Bootstrap Blazor Component</h1>
<h1 align="center">Bootstrap Blazor Component</h1>
<div align="center">
<h2>A set of enterprise-class UI components based on Bootstrap and Blazor.</h2>
[![Github build](https://img.shields.io/github/workflow/status/ArgoZhang/BootstrapBlazor/Package%20to%20Nuget/master?label=master&logo=github&logoColor=green)](https://github.com/ArgoZhang/BootstrapAdmin/actions?query=workflow%3A%22Auto+Build+CI%22+branch%3Amaster)
[![Github build](https://img.shields.io/github/workflow/status/ArgoZhang/BootstrapBlazor/Build%20Project/main?label=main&logo=github&logoColor=green)](https://github.com/ArgoZhang/BootstrapBlazor/actions?query=workflow%3A%22Build+Project%22+branch%3Amain)
[![Nuget](https://img.shields.io/nuget/v/BootstrapBlazor.svg?color=red&logo=nuget&logoColor=green)](https://www.nuget.org/packages/BootstrapBlazor/)
[![Nuget](https://img.shields.io/nuget/dt/BootstrapBlazor.svg?logo=nuget&logoColor=green)](https://www.nuget.org/packages/BootstrapBlazor/)
[![Github](https://img.shields.io/github/license/argozhang/bootstrapblazor.svg?logo=git&logoColor=red)](https://github.com/ArgoZhang/BootstrapBlazor/blob/master/LICENSE)
[![Github](https://img.shields.io/github/license/argozhang/bootstrapblazor.svg?logo=git&logoColor=red)](https://github.com/ArgoZhang/BootstrapBlazor/blob/main/LICENSE)
[![Repo Size](https://img.shields.io/github/repo-size/ArgoZhang/BootstrapBlazor.svg?logo=github&logoColor=green&label=repo)](https://github.com/ArgoZhang/BootstrapBlazor)
[![Commit Date](https://img.shields.io/github/last-commit/ArgoZhang/BootstrapBlazor/master.svg?logo=github&logoColor=green&label=commit)](https://github.com/ArgoZhang/BootstrapBlazor)
[![Commit Date](https://img.shields.io/github/last-commit/ArgoZhang/BootstrapBlazor/main.svg?logo=github&logoColor=green&label=commit)](https://github.com/ArgoZhang/BootstrapBlazor)
</div>

View File

@@ -1,4 +1,18 @@
# Bootstrap Blazor Component
<h1 align="center">Bootstrap Blazor 组件库</h1>
<div align="center">
<h2>一套基于 Bootstrap 和 Blazor 的企业级组件库</h2>
[![Github build](https://img.shields.io/github/workflow/status/ArgoZhang/BootstrapBlazor/Build%20Project/main?label=main&logo=github&logoColor=green)](https://github.com/ArgoZhang/BootstrapBlazor/actions?query=workflow%3A%22Build+Project%22+branch%3Amain)
[![Nuget](https://img.shields.io/nuget/v/BootstrapBlazor.svg?color=red&logo=nuget&logoColor=green)](https://www.nuget.org/packages/BootstrapBlazor/)
[![Nuget](https://img.shields.io/nuget/dt/BootstrapBlazor.svg?logo=nuget&logoColor=green)](https://www.nuget.org/packages/BootstrapBlazor/)
[![Github](https://img.shields.io/github/license/argozhang/bootstrapblazor.svg?logo=git&logoColor=red)](https://github.com/ArgoZhang/BootstrapBlazor/blob/main/LICENSE)
[![Repo Size](https://img.shields.io/github/repo-size/ArgoZhang/BootstrapBlazor.svg?logo=github&logoColor=green&label=repo)](https://github.com/ArgoZhang/BootstrapBlazor)
[![Commit Date](https://img.shields.io/github/last-commit/ArgoZhang/BootstrapBlazor/main.svg?logo=github&logoColor=green&label=commit)](https://github.com/ArgoZhang/BootstrapBlazor)
</div>
---
<a href="README.md">English</a> | <span>中文</span>
@@ -29,8 +43,16 @@ Blazor 是一个使用 .NET 生成交互式客户端 Web UI 的框架:
3. 获取本项目代码 [BootstrapBlazor](https://gitee.com/LongbowEnterprise/BootstrapBlazor)
## 相关资源
- [Blazor 官方文档](https://docs.microsoft.com/zh-cn/aspnet/core/blazor/?WT.mc_id=DT-MVP-5004174)
- [MS Learn 平台 Blazor 教程](https://docs.microsoft.com/zh-cn/learn/modules/build-blazor-webassembly-visual-studio-code/?WT.mc_id=DT-MVP-5004174)
- [生成 Blazor Web 应用](https://docs.microsoft.com/zh-cn/learn/modules/build-blazor-webassembly-visual-studio-code/?WT.mc_id=DT-MVP-5004174)
- [什么是 Blazor](https://docs.microsoft.com/zh-cn/learn/modules/build-blazor-webassembly-visual-studio-code/2-understand-blazor-webassembly?WT.mc_id=DT-MVP-5004174)
- [练习 - 配置开发环境](https://docs.microsoft.com/zh-cn/learn/modules/build-blazor-webassembly-visual-studio-code/3-exercise-configure-enviromnent?WT.mc_id=DT-MVP-5004174)
- [Blazor 组件](https://docs.microsoft.com/zh-cn/learn/modules/build-blazor-webassembly-visual-studio-code/4-blazor-components?WT.mc_id=DT-MVP-5004174)
- [练习 - 添加组件](https://docs.microsoft.com/zh-cn/learn/modules/build-blazor-webassembly-visual-studio-code/5-exercise-add-component?WT.mc_id=DT-MVP-5004174)
- [数据绑定和事件](https://docs.microsoft.com/zh-cn/learn/modules/build-blazor-webassembly-visual-studio-code/6-csharp-razor-binding?WT.mc_id=DT-MVP-5004174)
- [练习 - 数据绑定和事件](https://docs.microsoft.com/zh-cn/learn/modules/build-blazor-webassembly-visual-studio-code/7-exercise-razor-binding?WT.mc_id=DT-MVP-5004174)
- [总结](https://docs.microsoft.com/zh-cn/learn/modules/build-blazor-webassembly-visual-studio-code/8-summary?WT.mc_id=DT-MVP-5004174)
## QQ交流群

View File

@@ -2,6 +2,7 @@
cd ~/BootstrapBlazor
git pull
dotnet restore --no-cache
dotnet publish src/BootstrapBlazor.WebConsole -c Release
systemctl stop ba.blazor

View File

@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<IsWebProject>true</IsWebProject>
</PropertyGroup>
@@ -10,7 +9,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Longbow.Tasks" Version="5.0.0" />
<PackageReference Include="Longbow.Tasks" Version="5.0.1" />
</ItemGroup>
<ItemGroup>

View File

@@ -6,6 +6,7 @@ using BootstrapBlazor.Shared;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
@@ -26,10 +27,17 @@ namespace BootstrapBlazor.Server.Controllers.Api
/// <param name="options"></param>
/// <returns></returns>
[HttpGet]
public Task<string> Get([FromQuery] string fileName, [FromServices] HttpClient client, [FromServices] IOptions<WebsiteOptions> options)
public async Task<string> Get([FromQuery] string fileName, [FromServices] HttpClient client, [FromServices] IOptions<WebsiteOptions> options)
{
var ret = "";
client.BaseAddress = new Uri(options.Value.RepositoryUrl);
return client.GetStringAsync(fileName);
try
{
ret = await client.GetStringAsync(fileName);
}
catch (HttpRequestException ex) { ret = ex.StatusCode == HttpStatusCode.NotFound ? "无" : ex.StatusCode.ToString() ?? "网络错误"; }
catch (Exception) { }
return ret;
}
/// <summary>

View File

@@ -1,29 +0,0 @@
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Website: https://www.blazor.zone or https://argozhang.github.io/
using Microsoft.Extensions.DependencyInjection.Extensions;
namespace Microsoft.Extensions.DependencyInjection
{
/// <summary>
///
/// </summary>
internal static class CultureStorageExtensions
{
/// <summary>
/// 添加本地化持久化策略服务
/// </summary>
/// <param name="services"></param>
public static IServiceCollection AddCultureStorage(this IServiceCollection services)
{
services.TryAddSingleton<ICultureStorage, DefaultCultureStorage>();
return services;
}
internal class DefaultCultureStorage : ICultureStorage
{
public CultureStorageMode Mode { get; set; }
}
}
}

View File

@@ -21,11 +21,11 @@
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
<link rel="apple-touch-icon" href="favicon.png">
<base href="~/">
<link rel="stylesheet" href="_content/BootstrapBlazor.Chart/css/bootstrap.blazor.chart.bundle.min.css">
<link rel="stylesheet" href="_content/BootstrapBlazor.Markdown/css/bootstrap.blazor.markdown.min.css">
<link rel="stylesheet" href="_content/BootstrapBlazor/css/bootstrap.blazor.bundle.min.css">
<link rel="stylesheet" href="_content/BootstrapBlazor.Shared/lib/highlight/vs.css">
<link rel="stylesheet" href="_content/BootstrapBlazor.Shared/css/site.css">
<link rel="stylesheet" href="_content/BootstrapBlazor/css/bootstrap.blazor.bundle.min.css" asp-append-version="true">
<link rel="stylesheet" href="_content/BootstrapBlazor.Chart/css/bootstrap.blazor.chart.bundle.min.css" asp-append-version="true">
<link rel="stylesheet" href="_content/BootstrapBlazor.Markdown/css/bootstrap.blazor.markdown.min.css" asp-append-version="true">
<link rel="stylesheet" href="_content/BootstrapBlazor.Shared/lib/highlight/vs.css" asp-append-version="true">
<link rel="stylesheet" href="_content/BootstrapBlazor.Shared/css/site.css" asp-append-version="true">
<environment include="Staging,Production">
<script>
var _hmt = _hmt || [];
@@ -53,14 +53,15 @@
<a href="" class="reload">Reload</a>
<a class="dismiss"><i class="fa fa-times"></i></a>
</div>
<script src="_framework/blazor.server.js"></script>
<script src="_content/BootstrapBlazor/js/bootstrap.blazor.bundle.min.js"></script>
<script src="_content/BootstrapBlazor.Chart/js/bootstrap.blazor.chart.bundle.min.js"></script>
<script src="_content/BootstrapBlazor.TableExport/js/export.min.js"></script>
<script src="_content/BootstrapBlazor.Markdown/js/bootstrap.blazor.markdown.min.js"></script>
<script src="_content/BootstrapBlazor.Shared/lib/highlight/highlight.min.js"></script>
<script src="_content/BootstrapBlazor.Shared/lib/summernote/summernote-zh-CN.min.js"></script>
<script src="_content/BootstrapBlazor.Shared/js/common.js"></script>
<div class="wwads-cn wwads-horizontal" data-id="72" style="max-width:350px"></div>
<script src="_content/BootstrapBlazor/js/bootstrap.blazor.bundle.min.js" asp-append-version="true"></script>
<script src="_content/BootstrapBlazor.Chart/js/bootstrap.blazor.chart.bundle.min.js" asp-append-version="true"></script>
<script src="_content/BootstrapBlazor.TableExport/js/export.min.js" asp-append-version="true"></script>
<script src="_content/BootstrapBlazor.Markdown/js/bootstrap.blazor.markdown.min.js" asp-append-version="true"></script>
<script src="_content/BootstrapBlazor.Shared/lib/highlight/highlight.min.js" asp-append-version="true"></script>
<script src="_content/BootstrapBlazor.Shared/lib/summernote/summernote-zh-CN.min.js" asp-append-version="true"></script>
<script src="_content/BootstrapBlazor.Shared/js/common.js" asp-append-version="true"></script>
<script src="_framework/blazor.server.js" asp-append-version="true"></script>
<script src="https://wwads.cn/js/makemoney.js" type="text/javascript" async></script>
</body>
</html>

View File

@@ -11,6 +11,8 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace BootstrapBlazor.Server
@@ -55,7 +57,6 @@ namespace BootstrapBlazor.Server
services.AddControllers();
services.AddRazorPages();
services.AddServerSideBlazor();
services.AddCultureStorage();
services.AddBlazorBackgroundTask();
@@ -64,7 +65,9 @@ namespace BootstrapBlazor.Server
{
// 统一设置 Toast 组件自动消失时间
options.ToastDelay = 4000;
options.Themes.Add(new System.Collections.Generic.KeyValuePair<string, string>("Ant Design (完善中)", "_content/BootstrapBlazor.Shared/css/ant.css"));
options.Themes.AddRange(Configuration.GetSection("Themes")
.GetChildren()
.Select(c => new KeyValuePair<string, string>(c.Key, c.Value)));
}, options =>
{
// 附加自己的 json 多语言文化资源文件 如 zh-TW.json

View File

@@ -7,6 +7,7 @@
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowOrigins": "http://localhost:5000",
"WebsiteOptions": {
"ServerUrl": "http://localhost:50853",
"WasmUrl": "http://localhost:50855"

View File

@@ -25,6 +25,12 @@
"ServerUrl": "https://www.blazor.zone",
"AdminUrl": "https://admin.blazor.zone",
"ImageLibUrl": "https://imgs.blazor.zone",
"WasmUrl": "https://wasm.blazor.zone"
"WasmUrl": "https://wasm.blazor.zone",
"TotalCount": 80
},
"Themes": {
"Ant Design (完善中)": "_content/BootstrapBlazor.Shared/css/ant.css",
"LayUI (完善中)": "_content/BootstrapBlazor.Shared/css/layui.css",
"Bluma (完善中)": "_content/BootstrapBlazor.Shared/css/bluma.css"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 335 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

View File

@@ -0,0 +1,102 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
<meta name="keywords" content="bootstrap,blazor,wasm,webassembly,UI,netcore,web,assembly">
<meta name="author" content="argo (argo@163.com)">
<title>Microsoft Docs Learn</title>
<link rel="icon" href="https://devblogs.microsoft.com/visualstudio/wp-content/uploads/sites/4/2018/10/Microsoft-Favicon.png" sizes="32x32">
<link rel="icon" href="https://devblogs.microsoft.com/visualstudio/wp-content/uploads/sites/4/2018/10/Microsoft-Favicon.png" sizes="192x192">
<link rel="apple-touch-icon" href="https://devblogs.microsoft.com/visualstudio/wp-content/uploads/sites/4/2018/10/Microsoft-Favicon.png">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css" integrity="sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l" crossorigin="anonymous">
<script>
var _hmt = _hmt || [];
(function () {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?f147c9b2e3e0cc2b629c6390e5ffe377";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
<style>
body {
background-color: #f4f4f4;
}
main {
padding: 60px 16%;
margin: 60px 0;
box-shadow: 2px 2px 8px rgb(0 0 0 / 10%);
border-radius: 4px;
background-color: #fff;
}
article h1 {
text-align: center;
font-size: 1.8rem;
margin-bottom: 1.5rem;
}
article h2 {
font-size: 1.5rem;
}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md">
<main>
<article>
<h1>Docs & Learn Champion Best Practice Story</h1>
<div class="text-center">
<img src="imgs/Argo-Circle.png" style="width: 60px;" />
</div>
<div class="text-center" style="font-size:1.25rem;">
<div class="mt-2">Guangpo Zhang</div>
<div class="mt-2 mb-3" style="font-size:0.875rem; color: #616161;">April 27th, 2021</div>
</div>
<p>
I am honored to be awarded as <a href="https://mvp.microsoft.com/en-us/PublicProfile/5004174" target="_blank">Microsoft MVP</a> on <b>March 1st, 2021</b>. Being MVP has always been my dream for a senior developer who has kept active in technical communities about 20 years.
</p>
<p>
As soon as I joined the program, my CPM Christina Liang contacted with me immediately and arranged the onboarding meeting to introduce MVP Program and Docs & Learn Champion project. I thought Docs & Learn Champion was a fantastic project, which can help more people know MS Learn free learning platform, where they can find a systemtic knowledge and tool resource, so I registered this activity at once. Before I received my Creator ID, I have chose a dozen of Docs articles, vedios and learning modules from MS Docs and Learn website, prepared the original URLs to add my Creator ID later. Christina said I was as active and energetic as the generation of post 90s. Haha, it is my habit to take action fast. As a startup partner, I am very busy at work, so I treasure every minute in part time to build several personal technical websites, organize community learning groups and record learning videos, so when I think one thing is worth doing, I will take action fast to make it true, and more people can benefit from it soon.
</p>
<p>
I was also astonished when Christina told me my score during March, with <b>3,287</b> total unique and <b>21,250</b> page views. Seeing so many visitors are interested in MS Learn content, I have momentum to contribute more on this thing. Maybe it is just because of my sharing, someone know Blazor and MS product and services, and will make use of it in their daily work and get achievement in the future. Thats what make us feel proud as a Microsoft MVP.
</p>
<img src="imgs/Picture1.png" class="w-100 py-3" />
<p>Let me share my experience how I can attract 3,000+ visitors to see MS Docs and Learn website during one month.</p>
<h2>Firstly</h2>
<p>
I add Docs links of Blazor official learning content at outsanding position on my persoanl website: <a href="https://www.blazor.zone" target="_blank">www.blazor.zone</a>, and I also made a popup box to introduce 8 important articles on Blazor, which beginner shall read them to have a general concept. Here is a small trick that I set up the popup box to cover some website content, most people would like to click them to have a look out of curiosity. Frankly speaking, they are very good learning content, and I highly recommend people to read them in my learning groups. The dashboard data says these 8 articles have got largest clicks, with each one over <b>3,200</b> views.
</p>
<img src="imgs/Picture2.png" class="w-100 py-3" />
<img src="imgs/Picture3.png" class="w-100 py-3" />
<h2>Secondly</h2>
<p>I made two large-scale updates and advertisement for my website in March, which attracted new visitors that took <b>71.94%</b> of all visitors and attributed high clicks on my website. As shown in the screenshot below, you can see the visitors of my website in March was about 10,000 making <b>93,010</b> page views, so my Docs & Learn Champion unique visitors and page views are divided by my website data, we could find the transfer rates were <b>35.90%</b> and <b>22.8%</b> separately for unique visitors and page views. High percentage of my website visitors are interested in MS Learn content. </p>
<img src="imgs/Picture7.png" class="w-100 py-3" />
<img src="imgs/Picture4.png" class="w-100 py-3" />
<h2>Thirdly</h2>
<p>I made search engine optimization for some key words to get a satisfied result. Now, if people search words, such as blazor bootstrap ui in Chinese famous search engine Baidu.com, they will be led to my website, and then have great probabilities to click MS Learn links I inserted there. </p>
<img src="imgs/Picture5.png" class="w-100 py-3" />
<h2>Fourthly</h2>
<p>
I organized Blazor community, and a number of learning groups. I would send MS Learn and Docs articles and modules into these community groups as learning material or answers to their questions. My hardworking administrators will also help me send these articles to group members. We are happy to receive members feedback that they felt the material is valuable and many of them sent screenshot to me showing they finished all modules.
</p>
<img src="imgs/Picture6.png" class="w-100 py-3" />
<h2>Fifthly</h2>
<p>I have several open-source projects, which will be updated every Thursday. I will send MS Learn content together with my open-source update news to the audience to share the popularity of update news, which usually attract over <b>2,000</b> views till next morning. </p>
<h2>Sixthly</h2>
<p>Taking a ride from official release. When .Net releases the preview version, people all actively discuss the new features, so I will post some blogs in the topic of these new features inserting MS Learn article links. For example, Microsoft recently released .Net preview 3 with hot reload feature, so I also post some blogs introducing blazor support hot reload and MS Learn courses. </p>
<p>All in all, as a newcomer, there are a lot of things to be learned from experienced MVPs and CPMs. I hope my sharing can provide you with some reference. Through joining Docs & Learn Champion, I am excited to see so many developers are interested in Microsoft products and services, as well as this fantastic free MS Learn platform. It is a continuously updated storehouse of practical knowledge, and I hope more people would know it, use it and connect with each other to progress through my sharing. </p>
</article>
</main>
</div>
</div>
</div>
</body>
</html>

View File

@@ -8,3 +8,5 @@
</LayoutView>
</NotFound>
</Router>
<Title></Title>

View File

@@ -4,6 +4,8 @@
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using System;
using System.Threading.Tasks;
namespace BootstrapBlazor.Shared
{
@@ -22,13 +24,13 @@ namespace BootstrapBlazor.Shared
///
/// </summary>
/// <param name="firstRender"></param>
protected override void OnAfterRender(bool firstRender)
protected override async Task OnAfterRenderAsync(bool firstRender)
{
base.OnAfterRender(firstRender);
await base.OnAfterRenderAsync(firstRender);
if (firstRender && JSRuntime != null)
if (firstRender && OperatingSystem.IsBrowser() && JSRuntime != null)
{
JSRuntime.InvokeVoidAsync("$.loading");
await JSRuntime.InvokeVoidAsync("$.loading");
}
}
}

View File

@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<IsPackable>true</IsPackable>
<Version>5.0.0</Version>
</PropertyGroup>
@@ -18,9 +17,9 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="BootstrapBlazor.Chart" Version="5.0.10" />
<PackageReference Include="BootstrapBlazor.Markdown" Version="5.0.10" />
<PackageReference Include="BootstrapBlazor.TableExport" Version="5.0.10" />
<PackageReference Include="BootstrapBlazor.Chart" Version="5.0.18" />
<PackageReference Include="BootstrapBlazor.Markdown" Version="5.0.18" />
<PackageReference Include="BootstrapBlazor.TableExport" Version="5.0.18" />
<PackageReference Include="System.Net.Http.Json" Version="5.0.0" />
</ItemGroup>

View File

@@ -34,8 +34,6 @@ namespace Microsoft.Extensions.DependencyInjection
{
private HttpClient Client { get; set; }
private bool IsWebAssembly { get; set; }
private string ServerUrl { get; set; }
/// <summary>
@@ -43,15 +41,13 @@ namespace Microsoft.Extensions.DependencyInjection
/// </summary>
/// <param name="client"></param>
/// <param name="options"></param>
/// <param name="storage"></param>
public ExampleService(HttpClient client, IOptions<WebsiteOptions> options, ICultureStorage storage)
public ExampleService(HttpClient client, IOptions<WebsiteOptions> options)
{
Client = client;
Client.Timeout = TimeSpan.FromSeconds(5);
Client.BaseAddress = new Uri(options.Value.RepositoryUrl);
ServerUrl = options.Value.ServerUrl;
IsWebAssembly = storage.Mode == CultureStorageMode.LocalStorage;
}
/// <summary>
@@ -63,7 +59,7 @@ namespace Microsoft.Extensions.DependencyInjection
var content = "";
try
{
if (IsWebAssembly)
if (OperatingSystem.IsBrowser())
{
Client.BaseAddress = new Uri($"{ServerUrl}/api/");
content = await Client.GetStringAsync($"Code?fileName={CodeFile}");
@@ -73,7 +69,8 @@ namespace Microsoft.Extensions.DependencyInjection
content = await Client.GetStringAsync(CodeFile);
}
}
catch (HttpRequestException) { content = ""; }
catch (HttpRequestException) { content = "网络错误"; }
catch (TaskCanceledException) { }
catch (Exception) { }
return content;
}

View File

@@ -3,9 +3,8 @@
// Website: https://www.blazor.zone or https://argozhang.github.io/
using BootstrapBlazor.Components;
using BootstrapBlazor.Shared.Pages;
using BootstrapBlazor.Shared.Pages.Components;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Localization;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
@@ -36,6 +35,13 @@ namespace Microsoft.Extensions.DependencyInjection
{
private List<TModel>? Items { get; set; }
private IStringLocalizer<TModel> Localizer { get; set; }
public TableDemoDataService(IStringLocalizer<TModel> localizer)
{
Localizer = localizer;
}
/// <summary>
/// 查询操作方法
/// </summary>
@@ -44,7 +50,10 @@ namespace Microsoft.Extensions.DependencyInjection
public override Task<QueryData<TModel>> QueryAsync(QueryPageOptions options)
{
// 此处代码实战中不可用,仅仅为演示而写
if (Items == null || Items.Count == 0) Items = TablesBase.GenerateItems().Cast<TModel>().ToList();
if (Items == null || Items.Count == 0)
{
Items = Foo.GenerateFoo((IStringLocalizer<Foo>)Localizer).Cast<TModel>().ToList();
}
var total = Items.Count;
@@ -108,7 +117,11 @@ namespace Microsoft.Extensions.DependencyInjection
public override Task<bool> DeleteAsync(IEnumerable<TModel> models)
{
foreach (var model in models) Items?.Remove(model);
foreach (var model in models)
{
Items?.Remove(model);
}
return base.DeleteAsync(models);
}
}

View File

@@ -92,6 +92,11 @@ namespace BootstrapBlazor.Shared
/// </summary>
public string CurrentTheme { get; set; } = "";
/// <summary>
/// 获得/设置 组件总数
/// </summary>
public int TotalCount { get; set; }
/// <summary>
/// 构造函数
/// </summary>

View File

@@ -1,103 +0,0 @@
{
"BootstrapBlazor.Shared.Pages.Components.Block": {
"Title": "",
"SubTitle": "Demo"
},
"BootstrapBlazor.Shared.Pages.Components.AttributeTable": {
"Title": "Attributes"
},
"BootstrapBlazor.Shared.Pages.Components.MethodTable": {
"Title": "Methods"
},
"BootstrapBlazor.Shared.Common.AttributeItem": {
"Name": "Parameter",
"Description": "Description",
"Type": "Type",
"ValueList": "ValueList",
"DefaultValue": "DefaultValue"
},
"BootstrapBlazor.Shared.Common.EventItem": {
"Name": "Parameter",
"Description": "Description",
"Type": "Type"
},
"BootstrapBlazor.Shared.Common.MethodItem": {
"Title": "Methods",
"Name": "Parameter",
"Description": "Description",
"Type": "Type",
"Parameters": "Parameters",
"ReturnValue": "ReturnValue"
},
"BootstrapBlazor.Shared.Shared.ComponentLayout": {
"Title": "Enterprise-level component library based on Bootstrap and Blazor",
"Example": "Example",
"Video": "Video"
},
"BootstrapBlazor.Shared.Pages.Alerts": {
"Title": "Alert",
"SubTitle": "Displays important alert messages.",
"BaseUsageText": "Basic usage",
"IntroText1": "Alert components are non-overlay elements in the page that does not disappear automatically.",
"AlertPrimaryText": "A simple primary alert—check it out!",
"AlertSecondaryText": "A simple secondary alert—check it out!",
"AlertSuccessText": "A simple success alert—check it out!",
"AlertDangerText": "A simple danger alert—check it out!",
"AlertWarningText": "A simple warning alert—check it out!",
"AlertInfoText": "A simple info alert—check it out!",
"AlertDarkText": "A simple dark alert—check it out!",
"CloseButtonUsageText": "Close button",
"IntroText2": "Customize the close button as texts or other symbols.",
"WithIconUsageText": "With Icon",
"IntroText3": "Displaying an icon improves readability.",
"ShowBarUsageText": "With Bar",
"IntroText4": "Show <code>Tip</code>"
},
"BootstrapBlazor.Shared.Pages.QRCodes": {
"Title": "QRCode",
"SubTitle": "Generate QR code",
"BaseUsageText": "Basic usage",
"IntroText1": "Click the Generate button to generate a <code>QRCode</code>",
"SuccessText": "QR code generated successfully",
"CallbackDescription": "Call back after QR code generation"
},
"BootstrapBlazor.Shared.Pages.Anchors": {
"Title": "Anchor",
"SubTitle": "Hyperlinks to scroll on one page.",
"BaseUsageText": "Basic usage",
"IntroText1": "For displaying anchor hyperlinks on page and jumping between them.",
"IntroText2": "Click <code>Anchor</code> item try it",
"ContentText1": "<p>Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p><p>Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor.</p><p>Aenean lacinia bibendum nulla sed consectetur. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Donec sed odio dui. Donec ullamcorper nulla non metus auctor fringilla.</p><p>Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p><p>Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor.</p>"
},
"BootstrapBlazor.Shared.Pages.Components.Foo": {
"Name": "Name",
"DateTime": "DateTime",
"Address": "Address",
"Count": "Count",
"Complete": "Complete",
"Education": "Education",
"Hobby": "Hobby",
"Name.Required": "{0} is required.",
"Address.Required": "{0} is required.",
"Education.Required": "{0} is required.",
"Hobby.Required": "{0} is required.",
"Name.PlaceHolder": "required",
"Hobbys": "Swimming,Climb,Shoot,Chess",
"Foo.Name": "Zhangsan {0}",
"Foo.Address": "Lane {0} of Jinshajiang Road, Putuo District, Shanghai",
"Foo.Address2": "Earth, China, Lane {0} of Jinshajiang Road, Putuo District, Shanghai. Here is an example of super long cell",
"Foo.BindValue": "BindValue"
},
"BootstrapBlazor.Shared.Pages.Components.EnumEducation": {
"PlaceHolder": "Click to select ...",
"Primary": "Primary",
"Middel": "Middel"
},
"BootstrapBlazor.Shared.Pages.Inputs": {
"PlaceHolder": "please input ..."
},
"BootstrapBlazor.Shared.Pages.Components.ThemeChooser": {
"Title": "Click to choose theme",
"HeaderText": "Themes"
}
}

View File

@@ -0,0 +1,284 @@
{
"BootstrapBlazor.Shared.App": {
"Title": "Bootstrap of Blazor"
},
"BootstrapBlazor.Shared.Pages.Components.Block": {
"Title": "",
"SubTitle": "Demo"
},
"BootstrapBlazor.Shared.Pages.Components.AttributeTable": {
"Title": "Attributes"
},
"BootstrapBlazor.Shared.Pages.Components.MethodTable": {
"Title": "Methods"
},
"BootstrapBlazor.Shared.Common.AttributeItem": {
"Name": "Parameter",
"Description": "Description",
"Type": "Type",
"ValueList": "ValueList",
"DefaultValue": "DefaultValue"
},
"BootstrapBlazor.Shared.Common.EventItem": {
"Name": "Parameter",
"Description": "Description",
"Type": "Type"
},
"BootstrapBlazor.Shared.Common.MethodItem": {
"Title": "Methods",
"Name": "Parameter",
"Description": "Description",
"Type": "Type",
"Parameters": "Parameters",
"ReturnValue": "ReturnValue"
},
"BootstrapBlazor.Shared.Shared.ComponentLayout": {
"Title": "Enterprise-level component library based on Bootstrap and Blazor",
"Example": "Example",
"Video": "Video"
},
"BootstrapBlazor.Shared.Pages.Alerts": {
"Title": "Alert",
"SubTitle": "Displays important alert messages.",
"BaseUsageText": "Basic usage",
"IntroText1": "Alert components are non-overlay elements in the page that does not disappear automatically.",
"AlertPrimaryText": "A simple primary alert—check it out!",
"AlertSecondaryText": "A simple secondary alert—check it out!",
"AlertSuccessText": "A simple success alert—check it out!",
"AlertDangerText": "A simple danger alert—check it out!",
"AlertWarningText": "A simple warning alert—check it out!",
"AlertInfoText": "A simple info alert—check it out!",
"AlertDarkText": "A simple dark alert—check it out!",
"CloseButtonUsageText": "Close button",
"IntroText2": "Customize the close button as texts or other symbols.",
"WithIconUsageText": "With Icon",
"IntroText3": "Displaying an icon improves readability.",
"ShowBarUsageText": "With Bar",
"IntroText4": "Show <code>Tip</code>"
},
"BootstrapBlazor.Shared.Pages.Selects": {
"PlaceHolder": "Not Select"
},
"BootstrapBlazor.Shared.Pages.QRCodes": {
"Title": "QRCode",
"SubTitle": "Generate QR code",
"BaseUsageText": "Basic usage",
"IntroText1": "Click the Generate button to generate a <code>QRCode</code>",
"SuccessText": "QR code generated successfully",
"CallbackDescription": "Call back after QR code generation"
},
"BootstrapBlazor.Shared.Pages.Anchors": {
"Title": "Anchor",
"SubTitle": "Hyperlinks to scroll on one page.",
"BaseUsageText": "Basic usage",
"IntroText1": "For displaying anchor hyperlinks on page and jumping between them.",
"IntroText2": "Click <code>Anchor</code> item try it",
"ContentText1": "<p>Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p><p>Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor.</p><p>Aenean lacinia bibendum nulla sed consectetur. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Donec sed odio dui. Donec ullamcorper nulla non metus auctor fringilla.</p><p>Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p><p>Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor.</p>"
},
"BootstrapBlazor.Shared.Pages.Components.Foo": {
"Name": "Name",
"DateTime": "DateTime",
"Address": "Address",
"Count": "Count",
"Complete": "Complete",
"Education": "Education",
"Hobby": "Hobby",
"Name.Required": "{0} is required.",
"Address.Required": "{0} is required.",
"Education.Required": "{0} is required.",
"Hobby.Required": "{0} is required.",
"Name.PlaceHolder": "required",
"Hobbys": "Swimming,Climb,Shoot,Chess",
"Foo.Name": "Zhangsan {0}",
"Foo.Address": "Lane {0} of Jinshajiang Road, Putuo District, Shanghai",
"Foo.Address2": "Earth, China, Lane {0} of Jinshajiang Road, Putuo District, Shanghai. Here is an example of super long cell",
"Foo.BindValue": "BindValue"
},
"BootstrapBlazor.Shared.Pages.ValidateForms.ComplexFoo": {
"Name": "Name",
"Name.Required": "{0} is required."
},
"BootstrapBlazor.Shared.Pages.ValidateForms.Dummy2": {
"Name": "Name",
"Name.Required": "Dummy2 {0} is required"
},
"BootstrapBlazor.Shared.Pages.Components.EnumEducation": {
"PlaceHolder": "Click to select ...",
"Primary": "Primary",
"Middel": "Middel"
},
"BootstrapBlazor.Shared.Pages.Inputs": {
"PlaceHolder": "please input ..."
},
"BootstrapBlazor.Shared.Pages.Components.ThemeChooser": {
"Title": "Click to choose theme",
"HeaderText": "Themes"
},
"BootstrapBlazor.Shared.Pages.Uploads.Person": {
"Name": "Name",
"Name.Required": "{0} is required",
"Picture": "File",
"Picture.Required": "{0} is required"
},
"BootstrapBlazor.Shared.Pages.Components.CultureChooser": {
"Label": "Language"
},
"BootstrapBlazor.Shared.Shared.BaseLayout": {
"DownloadText": "Download",
"HomeText": "Home",
"IntroductionText": "Documents",
"ComponentsText": "Components",
"FlowText": "Workflow",
"InstallAppText": "Install PWA App",
"InstallText": "Install",
"CancelText": "Cancel"
},
"BootstrapBlazor.Shared.Shared.NavMenu": {
"GetStarted": "GETTINGSTARTED",
"Introduction": "Introduction",
"Install": "Install",
"ProjectTemplate": "Template",
"Globalization": "Globalization",
"Localization": "Localization",
"ServerBlazor": "Server-side Blazor",
"ClientBlazor": "Client-side Blazor",
"Labels": "Labels",
"LayoutPage": "LayoutPage",
"Components": "COMPONENTS",
"LayoutComponents": "LAYOUTS",
"Divider": "Divider",
"Layout": "Layout",
"Footer": "Footer",
"Row": "Row",
"Scroll": "Scroll",
"Skeleton": "Skeleton",
"Split": "Split",
"NavigationComponents": "NAVIGATIONS",
"Anchor": "Anchor",
"Breadcrumb": "Breadcrumb",
"Dropdown": "Dropdown",
"GoTop": "GoTop",
"Menu": "Menu",
"Nav": "Nav",
"Pagination": "Pagination",
"Steps": "Steps",
"Tab": "Tab",
"NotificationComponents": "NOTIFICATIONS",
"Alert": "Alert",
"Console": "Console",
"Dialog": "Dialog",
"Drawer": "Drawer",
"EditDialog": "EditDialog",
"Message": "Message",
"Modal": "Modal",
"Light": "Light",
"Popconfirm": "Popconfirm",
"Progress": "Progress",
"SearchDialog": "SearchDialog",
"Spinner": "Spinner",
"SweetAlert": "SweetAlert",
"Timer": "Timer",
"Toast": "Toast",
"FormsComponents": "FORMS",
"AutoComplete": "AutoComplete",
"Button": "Button",
"Cascader": "Cascader",
"Checkbox": "Checkbox",
"CheckboxList": "CheckboxList",
"ColorPicker": "ColorPicker",
"DateTimePicker": "DateTimePicker",
"DateTimeRange": "DateTimeRange",
"Editor": "Editor",
"EditorForm": "EditorForm",
"Input": "Input",
"InputNumber": "InputNumber",
"Markdown": "Markdown",
"MultiSelect": "MultiSelect",
"Radio": "Radio",
"Rate": "Rate",
"Select": "Select",
"Slider": "Slider",
"Switch": "Switch",
"Textarea": "Textarea",
"Toggle": "Toggle",
"Transfer": "Transfer",
"Upload": "Upload",
"ValidateForm": "ValidateForm",
"DataComponents": "DATAS",
"Avatar": "Avatar",
"Badge": "Badge",
"BarcodeReader": "BarcodeReader",
"Card": "Card",
"Calendar": "Calendar",
"Camera": "Camera",
"Captcha": "Captcha",
"Carousel": "Carousel",
"Chart": "Chart",
"Circle": "Circle",
"Collapse": "Collapse",
"Display": "Display",
"DropdownWidget": "DropdownWidget",
"GroupBox": "GroupBox",
"HandwrittenPage": "HandwrittenPage",
"ListView": "ListView",
"Popover": "Popover",
"QRCode": "QRCode",
"Search": "Search",
"Tag": "Tag",
"Timeline": "Timeline",
"Title": "Title",
"Download": "Download",
"Tooltip": "Tooltip",
"Tree": "Tree",
"Table": "Table",
"TableBase": "Base",
"TableRow": "Row",
"TableColumn": "Column",
"TableDetail": "Detail",
"TableSearch": "Search",
"TableFilter": "Sort/Filter",
"TableFixHeader": "FixHeader",
"TableHeaderGroup": "HeaderGroup",
"TableFixColumn": "FixColumn",
"TablePage": "Pagination",
"TableToolbar": "Toolbar",
"TableEdit": "Edit",
"TableExport": "Export",
"TableSelection": "Selection",
"TableAutoRefresh": "AutoRefresh",
"TableFooter": "Footer",
"TableDialog": "Table-Dialog",
"TableWrap": "Wrap",
"TableTree": "Table-Tree",
"TableLaoding": "Table-Loading",
"MenuAccordion": "Accordion",
"MenuExpandAll": "Expand"
},
"BootstrapBlazor.Shared.Pages.Menus": {
"System": "System",
"Website": "Website",
"Task": "Task",
"Authorize": "Authorize",
"User": "User",
"Menu": "Menu",
"Role": "Role",
"Log": "Log",
"Access": "Access",
"Login": "Login",
"Operation": "Operation",
"Nav1": "Menu 1",
"Nav2": "Menu 2",
"Nav3": "Menu 3",
"SubMenu1": "Sub Menu 1",
"SubMenu2": "Sub Menu 2",
"SubMenu3": "Sub Menu 3",
"SubMenu11": "Sub Menu 11",
"SubMenu12": "Sub Menu 12",
"SubMenu21": "Sub Menu 21",
"SubMenu22": "Sub Menu 22",
"SubMenu31": "Sub Menu 31",
"SubMenu32": "Sub Menu 32",
"SubMenu41": "Sub Menu 41",
"SubMenu42": "Sub Menu 42"
}
}

View File

@@ -1,103 +0,0 @@
{
"BootstrapBlazor.Shared.Pages.Components.Block": {
"Title": "未设置",
"SubTitle": "示例"
},
"BootstrapBlazor.Shared.Pages.Components.AttributeTable": {
"Title": "Attributes 属性"
},
"BootstrapBlazor.Shared.Pages.Components.MethodTable": {
"Title": "Methods 方法"
},
"BootstrapBlazor.Shared.Common.AttributeItem": {
"Name": "参数",
"Description": "说明",
"Type": "类型",
"ValueList": "可选值",
"DefaultValue": "默认值"
},
"BootstrapBlazor.Shared.Common.EventItem": {
"Name": "参数",
"Description": "说明",
"Type": "类型"
},
"BootstrapBlazor.Shared.Common.MethodItem": {
"Title": "Methods 方法",
"Name": "参数",
"Description": "说明",
"Type": "类型",
"Parameters": "参数",
"ReturnValue": "返回值"
},
"BootstrapBlazor.Shared.Shared.ComponentLayout": {
"Title": "基于 Bootstrap 和 Blazor 的企业级组件库",
"Example": "示例",
"Video": "相关视频"
},
"BootstrapBlazor.Shared.Pages.Alerts": {
"Title": "Alert 警告",
"SubTitle": "用于页面中展示重要的提示信息。",
"BaseUsageText": "基本用法",
"IntroText1": "页面中的非浮层元素,不会自动消失。",
"AlertPrimaryText": "主要的警告框",
"AlertSecondaryText": "次要的警告框",
"AlertSuccessText": "成功的警告框",
"AlertDangerText": "危险的警告框",
"AlertWarningText": "警告的警告框",
"AlertInfoText": "信息的警告框",
"AlertDarkText": "黑暗的警告框",
"CloseButtonUsageText": "关闭按钮",
"IntroText2": "提供关闭按钮的警告框",
"WithIconUsageText": "带 Icon",
"IntroText3": "表示某种状态时提升可读性。",
"ShowBarUsageText": "显示左侧 Bar",
"IntroText4": "作为 <code>Tip</code> 使用"
},
"BootstrapBlazor.Shared.Pages.QRCodes": {
"Title": "QRCode 二维码",
"SubTitle": "用于二维码生成",
"BaseUsageText": "基本用法",
"IntroText1": "点击生成按钮,生成特定的 <code>QRCode</code>",
"SuccessText": "二维码生成成功",
"CallbackDescription": "二维码生成后回调委托"
},
"BootstrapBlazor.Shared.Pages.Anchors": {
"Title": "Anchor 锚点",
"SubTitle": "用于跳转到页面指定位置",
"BaseUsageText": "基本用法",
"IntroText1": "需要展现当前页面上可供跳转的锚点链接,以及快速在锚点之间跳转",
"IntroText2": "点击下面 <code>Anchor</code> 项目,页面滚动到相对应的章节",
"ContentText1": "<p>与现实生活一致:与现实生活的流程、逻辑保持一致,遵循用户习惯的语言和概念;在界面中一致:所有的元素和结构需保持一致,比如:设计样式、图标和文本、元素的位置等。</p><p>控制反馈:通过界面样式和交互动效让用户可以清晰的感知自己的操作;</p><p>页面反馈:操作后,通过页面元素的变化清晰地展现当前状态。</p><p>简化流程:设计简洁直观的操作流程;</p><p>清晰明确:语言表达清晰且表意明确,让用户快速理解进而作出决策;</p><p>帮助用户识别:界面简单直白,让用户快速识别而非回忆,减少用户记忆负担。</p>"
},
"BootstrapBlazor.Shared.Pages.Components.Foo": {
"Name": "姓名",
"DateTime": "日期",
"Address": "地址",
"Count": "数量",
"Complete": "是/否",
"Education": "学历",
"Hobby": "爱好",
"Name.Required": "{0}是必填项",
"Address.Required": "{0}是必填项",
"Education.Required": "{0}是必选项",
"Hobby.Required": "请选择一种{0}",
"Name.PlaceHolder": "不可为空",
"Hobbys": "游泳,登山,打球,下棋",
"Foo.Name": "张三 {0}",
"Foo.Address": "上海市普陀区金沙江路 {0} 弄",
"Foo.Address2": "地球、中国、上海市普陀区金沙江路 {0} 弄 这里是超长单元格示例",
"Foo.BindValue": "绑定值"
},
"BootstrapBlazor.Shared.Pages.Components.EnumEducation": {
"PlaceHolder": "请选择 ...",
"Primary": "小学",
"Middel": "中学"
},
"BootstrapBlazor.Shared.Pages.Inputs": {
"PlaceHolder": "请输入 ..."
},
"BootstrapBlazor.Shared.Pages.Components.ThemeChooser": {
"Title": "点击切换主题",
"HeaderText": "请选择主题"
}
}

View File

@@ -0,0 +1,284 @@
{
"BootstrapBlazor.Shared.App": {
"Title": "Bootstrap Blazor - 企业级 UI 组件库"
},
"BootstrapBlazor.Shared.Pages.Components.Block": {
"Title": "未设置",
"SubTitle": "示例"
},
"BootstrapBlazor.Shared.Pages.Components.AttributeTable": {
"Title": "Attributes 属性"
},
"BootstrapBlazor.Shared.Pages.Components.MethodTable": {
"Title": "Methods 方法"
},
"BootstrapBlazor.Shared.Common.AttributeItem": {
"Name": "参数",
"Description": "说明",
"Type": "类型",
"ValueList": "可选值",
"DefaultValue": "默认值"
},
"BootstrapBlazor.Shared.Common.EventItem": {
"Name": "参数",
"Description": "说明",
"Type": "类型"
},
"BootstrapBlazor.Shared.Common.MethodItem": {
"Title": "Methods 方法",
"Name": "参数",
"Description": "说明",
"Type": "类型",
"Parameters": "参数",
"ReturnValue": "返回值"
},
"BootstrapBlazor.Shared.Shared.ComponentLayout": {
"Title": "基于 Bootstrap 和 Blazor 的企业级组件库",
"Example": "示例",
"Video": "相关视频"
},
"BootstrapBlazor.Shared.Pages.Alerts": {
"Title": "Alert 警告",
"SubTitle": "用于页面中展示重要的提示信息。",
"BaseUsageText": "基本用法",
"IntroText1": "页面中的非浮层元素,不会自动消失。",
"AlertPrimaryText": "主要的警告框",
"AlertSecondaryText": "次要的警告框",
"AlertSuccessText": "成功的警告框",
"AlertDangerText": "危险的警告框",
"AlertWarningText": "警告的警告框",
"AlertInfoText": "信息的警告框",
"AlertDarkText": "黑暗的警告框",
"CloseButtonUsageText": "关闭按钮",
"IntroText2": "提供关闭按钮的警告框",
"WithIconUsageText": "带 Icon",
"IntroText3": "表示某种状态时提升可读性。",
"ShowBarUsageText": "显示左侧 Bar",
"IntroText4": "作为 <code>Tip</code> 使用"
},
"BootstrapBlazor.Shared.Pages.Selects": {
"PlaceHolder": "未选择"
},
"BootstrapBlazor.Shared.Pages.QRCodes": {
"Title": "QRCode 二维码",
"SubTitle": "用于二维码生成",
"BaseUsageText": "基本用法",
"IntroText1": "点击生成按钮,生成特定的 <code>QRCode</code>",
"SuccessText": "二维码生成成功",
"CallbackDescription": "二维码生成后回调委托"
},
"BootstrapBlazor.Shared.Pages.Anchors": {
"Title": "Anchor 锚点",
"SubTitle": "用于跳转到页面指定位置",
"BaseUsageText": "基本用法",
"IntroText1": "需要展现当前页面上可供跳转的锚点链接,以及快速在锚点之间跳转",
"IntroText2": "点击下面 <code>Anchor</code> 项目,页面滚动到相对应的章节",
"ContentText1": "<p>与现实生活一致:与现实生活的流程、逻辑保持一致,遵循用户习惯的语言和概念;在界面中一致:所有的元素和结构需保持一致,比如:设计样式、图标和文本、元素的位置等。</p><p>控制反馈:通过界面样式和交互动效让用户可以清晰的感知自己的操作;</p><p>页面反馈:操作后,通过页面元素的变化清晰地展现当前状态。</p><p>简化流程:设计简洁直观的操作流程;</p><p>清晰明确:语言表达清晰且表意明确,让用户快速理解进而作出决策;</p><p>帮助用户识别:界面简单直白,让用户快速识别而非回忆,减少用户记忆负担。</p>"
},
"BootstrapBlazor.Shared.Pages.Components.Foo": {
"Name": "姓名",
"DateTime": "日期",
"Address": "地址",
"Count": "数量",
"Complete": "是/否",
"Education": "学历",
"Hobby": "爱好",
"Name.Required": "{0}是必填项",
"Address.Required": "{0}是必填项",
"Education.Required": "{0}是必选项",
"Hobby.Required": "请选择一种{0}",
"Name.PlaceHolder": "不可为空",
"Hobbys": "游泳,登山,打球,下棋",
"Foo.Name": "张三 {0}",
"Foo.Address": "上海市普陀区金沙江路 {0} 弄",
"Foo.Address2": "地球、中国、上海市普陀区金沙江路 {0} 弄 这里是超长单元格示例",
"Foo.BindValue": "绑定值"
},
"BootstrapBlazor.Shared.Pages.ValidateForms.ComplexFoo": {
"Name": "姓名",
"Name.Required": "{0} 值是必填项"
},
"BootstrapBlazor.Shared.Pages.ValidateForms.Dummy2": {
"Name": "姓名",
"Name.Required": "Dummy2 {0} 值是必填项"
},
"BootstrapBlazor.Shared.Pages.Components.EnumEducation": {
"PlaceHolder": "请选择 ...",
"Primary": "小学",
"Middel": "中学"
},
"BootstrapBlazor.Shared.Pages.Inputs": {
"PlaceHolder": "请输入 ..."
},
"BootstrapBlazor.Shared.Pages.Components.ThemeChooser": {
"Title": "点击切换主题",
"HeaderText": "请选择主题"
},
"BootstrapBlazor.Shared.Pages.Uploads.Person": {
"Name": "姓名",
"Name.Required": "{0}不能为空",
"Picture": "上传文件",
"Picture.Required": "上传文件不能为空"
},
"BootstrapBlazor.Shared.Pages.Components.CultureChooser": {
"Label": "语言:"
},
"BootstrapBlazor.Shared.Shared.BaseLayout": {
"DownloadText": "Download",
"HomeText": "首页",
"IntroductionText": "文档",
"ComponentsText": "组件",
"FlowText": "工作流",
"InstallAppText": "安装小程序",
"InstallText": "安装",
"CancelText": "取消"
},
"BootstrapBlazor.Shared.Shared.NavMenu": {
"GetStarted": "快速上手",
"Introduction": "简介",
"Install": "类库安装",
"ProjectTemplate": "项目模板",
"Globalization": "全球化",
"Localization": "本地化",
"ServerBlazor": "服务器端模式",
"ClientBlazor": "客户端模式",
"Labels": "表单标签",
"LayoutPage": "后台模拟器",
"Components": "组件总览",
"LayoutComponents": "布局组件",
"Divider": "分割线 Divider",
"Layout": "布局组件 Layout",
"Footer": "页脚组件 Footer",
"Row": "行组件 Row",
"Scroll": "滚动条 Scroll",
"Skeleton": "骨架屏 Skeleton",
"Split": "分割面板 Split",
"NavigationComponents": "导航组件",
"Anchor": "锚点 Anchor",
"Breadcrumb": "面包屑 Breadcrumb",
"Dropdown": "下拉菜单 Dropdown",
"GoTop": "跳转组件 GoTop",
"Menu": "菜单 Menu",
"Nav": "导航栏 Nav",
"Pagination": "分页 Pagination",
"Steps": "步骤条 Steps",
"Tab": "标签页 Tab",
"NotificationComponents": "通知组件",
"Alert": "警告框 Alert",
"Console": "控制台 Console",
"Dialog": "对话框 Dialog",
"Drawer": "抽屉 Drawer",
"EditDialog": "编辑弹窗 EditDialog",
"Message": "消息框 Message",
"Modal": "模态框 Modal",
"Light": "指示灯 Light",
"Popconfirm": "确认框 Popconfirm",
"Progress": "进度条 Progress",
"SearchDialog": "搜索弹窗 SearchDialog",
"Spinner": "旋转图标 Spinner",
"SweetAlert": "模态弹框 SweetAlert",
"Timer": "计时器 Timer",
"Toast": "轻量弹窗 Toast",
"FormsComponents": "表单组件",
"AutoComplete": "自动完成 AutoComplete",
"Button": "按钮 Button",
"Cascader": "级联选择 Cascader",
"Checkbox": "多选框 Checkbox",
"CheckboxList": "多选框组 CheckboxList",
"ColorPicker": "颜色拾取器 ColorPicker",
"DateTimePicker": "时间框 DateTimePicker",
"DateTimeRange": "时间范围框 DateTimeRange",
"Editor": "富文本框 Editor",
"EditorForm": "表单编辑框 EditorForm",
"Input": "输入框 Input",
"InputNumber": "数字框 InputNumber",
"Markdown": "富文本框 Markdown",
"MultiSelect": "多项选择器 MultiSelect",
"Radio": "单选框 Radio",
"Rate": "评分 Rate",
"Select": "选择器 Select",
"Slider": "滑块 Slider",
"Switch": "开关 Switch",
"Textarea": "多行文本框 Textarea",
"Toggle": "开关 Toggle",
"Transfer": "穿梭框 Transfer",
"Upload": "上传组件 Upload",
"ValidateForm": "验证表单 ValidateForm",
"DataComponents": "数据组件",
"Avatar": "头像框 Avatar",
"Badge": "徽章 Badge",
"BarcodeReader": "条码扫描 BarcodeReader",
"Card": "卡片 Card",
"Calendar": "日历框 Calendar",
"Camera": "摄像头 Camera",
"Captcha": "验证码 Captcha",
"Carousel": "走马灯 Carousel",
"Chart": "图表 Chart",
"Circle": "进度环 Circle",
"Collapse": "折叠 Collapse",
"Display": "数据显示 Display",
"DropdownWidget": "挂件 DropdownWidget",
"GroupBox": "集合 GroupBox",
"HandwrittenPage": "手写组件 HandwrittenPage",
"ListView": "列表组件 ListView",
"Popover": "弹出窗 Popover",
"QRCode": "二维码 QRCode",
"Search": "搜索框 Search",
"Tag": "标签 Tag",
"Timeline": "时间线 Timeline",
"Title": "网站标题 Title",
"Download": "文件下载 Download",
"Tooltip": "工具条 Tooltip",
"Tree": "树形组件 Tree",
"Table": "表格组件",
"TableBase": "基本功能",
"TableRow": "行设置",
"TableColumn": "列设置",
"TableDetail": "明细行",
"TableSearch": "搜索功能",
"TableFilter": "筛选和排序",
"TableFixHeader": "固定表头",
"TableHeaderGroup": "表头分组",
"TableFixColumn": "固定列",
"TablePage": "分页功能",
"TableToolbar": "工具栏",
"TableEdit": "表单维护",
"TableExport": "导出功能",
"TableSelection": "行选中",
"TableAutoRefresh": "自动刷新",
"TableFooter": "统计合并",
"TableDialog": "弹窗联动",
"TableWrap": "折行演示",
"TableTree": "树形数据",
"TableLaoding": "数据加载",
"MenuAccordion": "手风琴效果",
"MenuExpandAll": "全部展开"
},
"BootstrapBlazor.Shared.Pages.Menus": {
"System": "系统设置",
"Website": "网站设置",
"Task": "任务设置",
"Authorize": "权限设置",
"User": "用户设置",
"Menu": "菜单设置",
"Role": "角色设置",
"Log": "日志设置",
"Access": "访问日志",
"Login": "登录日志",
"Operation": "操作日志",
"Menu1": "菜单一",
"Menu2": "菜单二",
"Menu3": "菜单三",
"SubMenu1": "子菜单 1",
"SubMenu2": "子菜单 2",
"SubMenu3": "子菜单 3",
"SubMenu11": "孙菜单 11",
"SubMenu12": "孙菜单 12",
"SubMenu21": "孙菜单 21",
"SubMenu22": "孙菜单 22",
"SubMenu31": "曾孙菜单 31",
"SubMenu32": "曾孙菜单 32",
"SubMenu41": "曾曾孙菜单 41",
"SubMenu42": "曾曾孙菜单 42"
}
}

View File

@@ -1,10 +1,7 @@
@inherits BootstrapComponentBase
@inject IOptions<BootstrapBlazorOptions> BootstrapOptions
@inject NavigationManager NavigationManager
@inject ICultureStorage CultureStorage
<div @attributes="@AdditionalAttributes" class="@ClassString">
<label>请选择语言:</label>
<label>@Label</label>
<Select Value="@SelectedCulture" OnSelectedItemChanged="@SetCulture">
<Options>
@foreach (var kv in BootstrapOptions.Value.GetSupportedCultures())
@@ -14,55 +11,3 @@
</Options>
</Select>
</div>
@code{
private string? ClassString => CssBuilder.Default("culture-selector")
.AddClassFromAttributes(AdditionalAttributes)
.Build();
private string SelectedCulture { get; set; } = CultureInfo.CurrentUICulture.Name;
private async Task SetCulture(SelectedItem item)
{
if (CultureStorage.Mode == CultureStorageMode.Webapi)
{
// 使用 api 方式 适用于 Server-Side 模式
if (SelectedCulture != item.Value)
{
var culture = item.Value;
var uri = new Uri(NavigationManager.Uri).GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped);
var query = $"?culture={Uri.EscapeDataString(culture)}&redirectUri={Uri.EscapeDataString(uri)}";
// use a path that matches your culture redirect controller from the previous steps
NavigationManager.NavigateTo("/Culture/SetCulture" + query, forceLoad: true);
}
}
else
{
var cultureName = item.Value;
if (cultureName != CultureInfo.CurrentCulture.Name)
{
await JSRuntime.InvokeVoidAsync(identifier: "$.blazorCulture.set", cultureName);
var culture = new CultureInfo(cultureName);
CultureInfo.CurrentCulture = culture;
CultureInfo.CurrentUICulture = culture;
NavigationManager.NavigateTo(NavigationManager.Uri, forceLoad: true);
}
}
}
private string GetDisplayName(CultureInfo culture)
{
return CultureStorage.Mode switch
{
CultureStorageMode.Webapi => culture.NativeName,
_ => culture.Name switch
{
"zh-CN" => "中文(中国)",
"en-US" => "English (United States)",
_ => ""
}
};
}
}

View File

@@ -0,0 +1,102 @@
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Website: https://www.blazor.zone or https://argozhang.github.io/
using BootstrapBlazor.Components;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options;
using Microsoft.JSInterop;
using System;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Threading.Tasks;
namespace BootstrapBlazor.Shared.Pages.Components
{
/// <summary>
///
/// </summary>
public partial class CultureChooser
{
[Inject]
[NotNull]
private IOptions<BootstrapBlazorOptions>? BootstrapOptions { get; set; }
[Inject]
[NotNull]
private IStringLocalizer<CultureChooser>? Localizer { get; set; }
[Inject]
[NotNull]
private NavigationManager? NavigationManager { get; set; }
private string? ClassString => CssBuilder.Default("culture-selector")
.AddClassFromAttributes(AdditionalAttributes)
.Build();
private string SelectedCulture { get; set; } = CultureInfo.CurrentUICulture.Name;
[NotNull]
private string? Label { get; set; }
/// <summary>
/// OnInitialized 方法
/// </summary>
protected override void OnInitialized()
{
base.OnInitialized();
Label ??= Localizer[nameof(Label)];
}
private async Task SetCulture(SelectedItem item)
{
if (OperatingSystem.IsBrowser())
{
var cultureName = item.Value;
if (cultureName != CultureInfo.CurrentCulture.Name)
{
await JSRuntime.InvokeVoidAsync(identifier: "$.blazorCulture.set", cultureName);
var culture = new CultureInfo(cultureName);
CultureInfo.CurrentCulture = culture;
CultureInfo.CurrentUICulture = culture;
NavigationManager.NavigateTo(NavigationManager.Uri, forceLoad: true);
}
}
else
{
// 使用 api 方式 适用于 Server-Side 模式
if (SelectedCulture != item.Value)
{
var culture = item.Value;
var uri = new Uri(NavigationManager.Uri).GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped);
var query = $"?culture={Uri.EscapeDataString(culture)}&redirectUri={Uri.EscapeDataString(uri)}";
// use a path that matches your culture redirect controller from the previous steps
NavigationManager.NavigateTo("/Culture/SetCulture" + query, forceLoad: true);
}
}
}
private static string GetDisplayName(CultureInfo culture)
{
string? ret;
if (OperatingSystem.IsBrowser())
{
ret = culture.Name switch
{
"zh-CN" => "中文(中国)",
"en-US" => "English (United States)",
_ => ""
};
}
else
{
ret = culture.NativeName;
}
return ret;
}
}
}

View File

@@ -4,45 +4,7 @@
<Select TValue="string" Items="@Items3" OnSelectedItemChanged="@OnCascadeBindSelectClick" />
</div>
<div class="form-group col-12 col-sm-6">
<Select @ref="Select2" TValue="string" Items="@Items2" />
<Select TValue="string" Items="@Items2" />
</div>
</div>
</div>
@code {
private Select<string>? Select2;
private readonly List<SelectedItem> Items2 = new List<SelectedItem>();
private readonly IEnumerable<SelectedItem> Items3 = new SelectedItem[]
{
new SelectedItem ("", "请选择 ..."),
new SelectedItem ("Beijing", "北京"),
new SelectedItem ("Shanghai", "上海")
};
/// <summary>
/// 级联绑定菜单
/// </summary>
/// <param name="item"></param>
private Task OnCascadeBindSelectClick(SelectedItem item)
{
Items2.Clear();
if (item.Value == "Beijing")
{
Items2.AddRange(new SelectedItem[]
{
new SelectedItem("1","朝阳区"),
new SelectedItem("2","海淀区"),
});
}
else if (item.Value == "Shanghai")
{
Items2.AddRange(new SelectedItem[]
{
new SelectedItem("1","静安区"),
new SelectedItem("2","黄浦区"),
});
}
Select2?.SetItems(Items2);
return Task.CompletedTask;
}
}

View File

@@ -0,0 +1,56 @@
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Website: https://www.blazor.zone or https://argozhang.github.io/
using BootstrapBlazor.Components;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace BootstrapBlazor.Shared.Pages.Components
{
/// <summary>
///
/// </summary>
public partial class CustomerSelectDialog
{
private IEnumerable<SelectedItem>? Items2;
private readonly IEnumerable<SelectedItem> Items3 = new SelectedItem[]
{
new SelectedItem ("", "请选择 ..."),
new SelectedItem ("Beijing", "北京"),
new SelectedItem ("Shanghai", "上海")
};
/// <summary>
/// 级联绑定菜单
/// </summary>
/// <param name="item"></param>
private async Task OnCascadeBindSelectClick(SelectedItem item)
{
// 模拟异步通讯获取数据
await Task.Delay(100);
if (item.Value == "Beijing")
{
Items2 = new SelectedItem[]
{
new SelectedItem("1","朝阳区"),
new SelectedItem("2","海淀区"),
};
}
else if (item.Value == "Shanghai")
{
Items2 = new SelectedItem[]
{
new SelectedItem("1","静安区"),
new SelectedItem("2","黄浦区"),
};
}
else
{
Items2 = Enumerable.Empty<SelectedItem>();
}
StateHasChanged();
}
}
}

View File

@@ -12,13 +12,6 @@
<EditorForm TModel="Foo">
<FieldItems>
<EditorItem @bind-Field="@context.Id" Editable="false" />
<EditorItem @bind-Field="@context.Complete">
<EditTemplate Context="value">
<div class="form-group col-12 col-sm-6">
<Switch @bind-Value="@(((Foo)value).Complete)" ShowInnerText="true" OnInnerText="是" OffInnerText="否" />
</div>
</EditTemplate>
</EditorItem>
<EditorItem @bind-Field="@context.Hobby" Data="@Hobbys" />
</FieldItems>
</EditorForm>

View File

@@ -0,0 +1,16 @@
<h3>无限弹窗示例</h3>
<Tab>
<TabItem Text="用户管理">
<div>我是用户管理 @Value</div>
<Button Text="弹窗" OnClick="@OnClickButton" />
</TabItem>
<TabItem Text="菜单管理">
<div>我是菜单管理</div>
<Button Text="弹窗" OnClick="@OnClickButton" />
</TabItem>
<TabItem Text="角色管理">
<div>我是角色管理</div>
<Button Text="弹窗" OnClick="@OnClickButton" />
</TabItem>
</Tab>

View File

@@ -0,0 +1,44 @@
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Website: https://www.blazor.zone or https://argozhang.github.io/
using BootstrapBlazor.Components;
using Microsoft.AspNetCore.Components;
using System;
using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
namespace BootstrapBlazor.Shared.Pages.Components
{
/// <summary>
///
/// </summary>
public partial class DialogDemo
{
/// <summary>
///
/// </summary>
[NotNull]
public string? Value { get; set; }
[Inject]
[NotNull]
private DialogService? DialogService { get; set; }
/// <summary>
/// OnInitialized 方法
/// </summary>
protected override void OnInitialized()
{
base.OnInitialized();
Value = DateTime.Now.ToString();
}
private Task OnClickButton() => DialogService.Show(new DialogOption()
{
Title = $"弹窗 {Value}",
Component = BootstrapDynamicComponent.CreateComponent<DialogDemo>()
});
}
}

View File

@@ -21,6 +21,7 @@ namespace BootstrapBlazor.Shared.Pages.Components
/// <summary>
///
/// </summary>
[Key]
[Display(Name = "主键")]
[AutoGenerateColumn(Ignore = true)]
public int Id { get; set; }
@@ -60,7 +61,7 @@ namespace BootstrapBlazor.Shared.Pages.Components
///
/// </summary>
[Display(Name = "是/否")]
[AutoGenerateColumn(Order = 50)]
[AutoGenerateColumn(Order = 50, ComponentType = typeof(Switch))]
public bool Complete { get; set; }
/// <summary>

View File

@@ -1,4 +1,4 @@
<Table TItem="Foo" Items="@Items.Take(10)" ClickToSelect="true" IsMultipleSelect="true" @bind-SelectedRows="@SelectedRows">
<Table TItem="Foo" ClickToSelect="true" IsMultipleSelect="true" @bind-SelectedRows="@SelectedRows" OnQueryAsync="@OnQueryAsync">
<TableColumns>
<TableColumn @bind-Field="@context.Id" />
<TableColumn @bind-Field="@context.Name" />

View File

@@ -37,7 +37,7 @@ namespace BootstrapBlazor.Shared.Pages.Components
public EventCallback<IEnumerable<string>> EmailsChanged { get; set; }
[CascadingParameter(Name = "BodyContext")]
private object? Count { get; set; }
private object? BodyContext { get; set; }
[Inject]
[NotNull]
@@ -50,12 +50,19 @@ namespace BootstrapBlazor.Shared.Pages.Components
{
base.OnInitialized();
Items = GenerateItems((int)(Count ?? 10));
Emails ??= Array.Empty<string>();
var context = BodyContext as FooContext;
Items = GenerateItems(context?.Count ?? 10);
Emails = context?.Emails?.Split(";") ?? Array.Empty<string>();
SelectedRows = Items.Where(i => Emails.Any(mail => mail == i.Email));
}
private Task<QueryData<Foo>> OnQueryAsync(QueryPageOptions option) => Task.FromResult(new QueryData<Foo>()
{
TotalCount = Items.Count(),
Items = Items
});
/// <summary>
///
/// </summary>
@@ -93,7 +100,7 @@ namespace BootstrapBlazor.Shared.Pages.Components
///
/// </summary>
/// <returns></returns>
protected static List<Foo> GenerateItems(int startId) => new List<Foo>(Enumerable.Range(startId, 10).Select(i => new Foo()
private static List<Foo> GenerateItems(int startId) => new(Enumerable.Range(startId, 10).Select(i => new Foo()
{
Id = i,
Name = $"张三 {i:d4}",
@@ -103,7 +110,23 @@ namespace BootstrapBlazor.Shared.Pages.Components
/// <summary>
///
/// </summary>
public class Foo
public class FooContext
{
/// <summary>
///
/// </summary>
public int Count { get; set; }
/// <summary>
///
/// </summary>
public string? Emails { get; set; }
}
/// <summary>
///
/// </summary>
private class Foo
{
/// <summary>
///

View File

@@ -1,10 +1,4 @@
@if (Count > 0)
{
<Badge Color="@BootstrapBlazor.Components.Color.Info" IsPill="true">
@Count
</Badge>
}
@if (IsNew)
@if (IsNew)
{
<span class="badge badge-danger">
<span>NEW</span>
@@ -16,3 +10,9 @@
<span>Upd</span>
</span>
}
@if (Count > 0)
{
<Badge Color="@BootstrapBlazor.Components.Color.Info" IsPill="true">
@Count
</Badge>
}

View File

@@ -39,9 +39,10 @@
<ComponentCard Text="表单组件 ValidateForm" Image="ValidateForm.png" Url="validateforms"></ComponentCard>
<ComponentCard Text="自动完成 AutoComplete" Image="AutoComplete.svg" Url="autocompletes"></ComponentCard>
<ComponentCard Text="按钮 Button" Image="Button.svg" Url="buttons"></ComponentCard>
<ComponentCard Text="级联选择 Button" Image="Cascader.svg" Url="cascaders"></ComponentCard>
<ComponentCard Text="级联选择 Cascader" Image="Cascader.png" Url="cascaders"></ComponentCard>
<ComponentCard Text="多选框 Checkbox" Image="CheckBox.svg" Url="checkboxs"></ComponentCard>
<ComponentCard Text="多选框组 CheckboxList" Image="CheckboxList.png" Url="checkboxlists"></ComponentCard>
<ComponentCard Text="颜色拾取器 ColorPicker" Image="ColorPicker.png" Url="colorpickers"></ComponentCard>
<ComponentCard Text="时间框 DateTimePicker" Image="DatePicker.svg" Url="datetimepickers"></ComponentCard>
<ComponentCard Text="时间范围框 DateTimeRange" Image="DateTimeRange.png" Url="datetimeranges"></ComponentCard>
<ComponentCard Text="富文本框 Editor" Image="Editor.png" Url="editors"></ComponentCard>
@@ -98,7 +99,7 @@
<ComponentCard Text="确认框 Popconfirm" Image="Popconfirm.svg" Url="popconfirms"></ComponentCard>
<ComponentCard Text="进度条 Progress" Image="Progress.svg" Url="progresss"></ComponentCard>
<ComponentCard Text="旋转图标 Spinner" Image="Spinner.gif" Url="spinners"></ComponentCard>
<ComponentCard Text="弹窗组件 SweetAlert" Image="SweetAlert.png" Url="swals"></ComponentCard>
<ComponentCard Text="模态弹窗 SweetAlert" Image="SweetAlert.png" Url="swals"></ComponentCard>
<ComponentCard Text="搜索弹窗 SearchDialog" Image="SearchDialog.png" Url="searchdialogs"></ComponentCard>
<ComponentCard Text="轻量弹窗 Toast" Image="Toast.png" Url="toasts"></ComponentCard>
<ComponentCard Text="计时器 Timer" Image="Timer.png" Url="timers"></ComponentCard>

View File

@@ -1,9 +1,10 @@
@using Microsoft.Extensions.Localization
@layout HomeLayout
@layout HomeLayout
@page "/"
@page "/index"
@page "/home"
<Title Text="@Localizer["Title"]"></Title>
<section class="home-section">
<div class="welcome container">
<div class="form-inline">
@@ -13,7 +14,7 @@
<h4>
Bootstrap 风格的 Blazor UI 组件库
</h4>
<div>基于 <code>Bootstrap</code> 样式库精心打造,并且额外增加了 76 多种常用的组件,为您快速开发项目带来非一般的感觉</div>
<div>基于 <code>Bootstrap</code> 样式库精心打造,并且额外增加了 @Options.Value.TotalCount 多种常用的组件,为您快速开发项目带来非一般的感觉</div>
<div class="welcome-body">
致力于打造全网<span @ref="TypeElement" class="typed"></span><span class="typed-cursor">|</span>
<div>最好玩的组件库</div>
@@ -127,8 +128,8 @@
<p class="d-none d-sm-block">
<img src="_content/BootstrapBlazor.Shared/images/components.svg" alt="components" />
</p>
<h3>50+ 组件</h3>
<div>本套组件库包含超过 50 多个组件,从简单的按钮到复杂的整页面级别的组件</div>
<h3>丰富组件</h3>
<div>本套组件库包含超过 @Options.Value.TotalCount 多个组件,从简单的按钮到复杂的整页面级别的组件</div>
</div>
</div>
<div class="form-group col-12 col-sm-6 col-md-4">

View File

@@ -3,7 +3,10 @@
// Website: https://www.blazor.zone or https://argozhang.github.io/
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options;
using Microsoft.JSInterop;
using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
namespace BootstrapBlazor.Shared.Pages
@@ -18,6 +21,14 @@ namespace BootstrapBlazor.Shared.Pages
[Inject]
private IJSRuntime? JSRuntime { get; set; }
[Inject]
[NotNull]
private IStringLocalizer<App>? Localizer { get; set; }
[Inject]
[NotNull]
private IOptions<WebsiteOptions>? Options { get; set; }
/// <summary>
///
/// </summary>
@@ -27,7 +38,10 @@ namespace BootstrapBlazor.Shared.Pages
{
await base.OnAfterRenderAsync(firstRender);
if (firstRender && JSRuntime != null) await JSRuntime.InvokeVoidAsync("$.indexTyper", TypeElement);
if (firstRender && JSRuntime != null)
{
await JSRuntime.InvokeVoidAsync("$.indexTyper", TypeElement);
}
}
}
}

View File

@@ -1,6 +1,7 @@
@page "/docs"
@page "/introduction"
@inject IOptions<WebsiteOptions> WebsiteOption
<h3>简介</h3>
<p>BootstrapBlazor 是一套基于 Bootstrap 和 Blazor 的企业级组件库,可以认为是 Bootstrap 项目的 Blazor 版实现。</p>

View File

@@ -30,7 +30,7 @@
<Block Title="展示类型" Introduction="支持三种类型:图标、图片和字符">
<div class="d-flex justify-content-between align-items-center">
<Avatar IsCircle="true" IsIcon="true" />
<Avatar IsCircle="true" IsIcon="true" Icon="fa fa-user" />
<Avatar IsCircle="true" Url="_content/BootstrapBlazor.Shared/images/Argo-C.png" />
<Avatar IsCircle="true" IsText="true" Text="User" />
</div>
@@ -47,4 +47,10 @@
<div>第二幅圆形头像加载图片路径错误,所以边框为 <b class="text-danger">红色</b>,图片显示为默认图标</div>
</Block>
<Block Title="异步加载" Introduction="适用于图片地址由 <code>webapi</code> 等接口异步获取的场景">
<div class="d-flex justify-content-between align-items-center">
<Avatar IsCircle="true" GetUrlAsync="@GetUrlAsync" />
</div>
</Block>
<AttributeTable Items="@GetAttributes()" />

View File

@@ -4,6 +4,7 @@
using BootstrapBlazor.Shared.Common;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace BootstrapBlazor.Shared.Pages
{
@@ -12,11 +13,17 @@ namespace BootstrapBlazor.Shared.Pages
/// </summary>
public sealed partial class Avatars
{
private async Task<string> GetUrlAsync()
{
// 模拟异步获取图像地址
await Task.Delay(500);
return "_content/BootstrapBlazor.Shared/images/Argo-C.png";
}
/// <summary>
/// 获得属性方法
/// </summary>
/// <returns></returns>
private IEnumerable<AttributeItem> GetAttributes() => new AttributeItem[]
private static IEnumerable<AttributeItem> GetAttributes() => new[]
{
// TODO: 移动到数据库中
new AttributeItem() {
@@ -74,6 +81,13 @@ namespace BootstrapBlazor.Shared.Pages
Type = "string",
ValueList = " — ",
DefaultValue = " — "
},
new AttributeItem() {
Name = "GetUrlAsync",
Description = "获取 Image 头像路径地址异步回调委托",
Type = "Func<Task<string>>",
ValueList = " — ",
DefaultValue = " — "
}
};
}

View File

@@ -154,6 +154,15 @@
</div>
</Block>
<Block Title="异步请求按钮" Introduction="通过设置 <code>IsAsync</code> 属性按钮是否为 <b>异步请求按钮</b>,默认为 <code>false</code>">
<p>当按钮为异步请求按钮时,点击按钮后自身状态会改变为禁用状态,同时显示 <code>Loading</code> 小图标,异步请求结束后恢复正常,本例中点击 <b>异步请求</b>按钮后显示请求加载动画5 秒后恢复正常</p>
<div class="row">
<div class="col">
<Button Text="异步请求" IsAsync="true" Icon="fa fa-fw fa-fa" OnClick="@ClickAsyncButton" />
</div>
</div>
</Block>
<AttributeTable Items="@GetAttributes()" />
<EventTable Items="@GetEvents()" />

View File

@@ -58,11 +58,13 @@ namespace BootstrapBlazor.Shared.Pages
return Task.CompletedTask;
}
private static Task ClickAsyncButton() => Task.Delay(5000);
/// <summary>
/// 获得事件方法
/// </summary>
/// <returns></returns>
private IEnumerable<EventItem> GetEvents() => new EventItem[]
private static IEnumerable<EventItem> GetEvents() => new EventItem[]
{
new EventItem()
{
@@ -82,7 +84,7 @@ namespace BootstrapBlazor.Shared.Pages
/// 获得属性方法
/// </summary>
/// <returns></returns>
private IEnumerable<AttributeItem> GetAttributes() => new AttributeItem[]
private static IEnumerable<AttributeItem> GetAttributes() => new AttributeItem[]
{
// TODO: 移动到数据库中
new AttributeItem() {
@@ -99,6 +101,13 @@ namespace BootstrapBlazor.Shared.Pages
ValueList = "",
DefaultValue = ""
},
new AttributeItem() {
Name = "LoadingIcon",
Description = "异步加载时的动画图标",
Type = "string",
ValueList = "",
DefaultValue = "fa fa-fw fa-spin fa-spinner"
},
new AttributeItem() {
Name = "Text",
Description = "显示文字",
@@ -141,6 +150,13 @@ namespace BootstrapBlazor.Shared.Pages
ValueList = " — ",
DefaultValue = "false"
},
new AttributeItem() {
Name = "IsAsync",
Description = "是否为异步按钮",
Type = "boolean",
ValueList = " — ",
DefaultValue = "false"
},
new AttributeItem() {
Name = "ChildContent",
Description = "内容",

View File

@@ -70,7 +70,7 @@ namespace BootstrapBlazor.Shared.Pages
/// 获得属性方法
/// </summary>
/// <returns></returns>
private IEnumerable<AttributeItem> GetAttributes() => new AttributeItem[]
private static IEnumerable<AttributeItem> GetAttributes() => new[]
{
// TODO: 移动到数据库中
new AttributeItem() {
@@ -149,7 +149,7 @@ namespace BootstrapBlazor.Shared.Pages
/// 获得事件方法
/// </summary>
/// <returns></returns>
private IEnumerable<EventItem> GetEvents() => new EventItem[]
private static IEnumerable<EventItem> GetEvents() => new[]
{
new EventItem()
{
@@ -163,7 +163,7 @@ namespace BootstrapBlazor.Shared.Pages
/// 获得事件方法
/// </summary>
/// <returns></returns>
private IEnumerable<MethodItem> GetMethods() => new MethodItem[]
private static IEnumerable<MethodItem> GetMethods() => new[]
{
new MethodItem()
{

View File

@@ -57,7 +57,7 @@ namespace BootstrapBlazor.Shared.Pages
if (firstRender && JSRuntime != null)
{
if (Interope == null) Interope = new JSInterop<Charts>(JSRuntime);
await Interope.Invoke(this, "", "_initChart", nameof(ShowToast));
await Interope.InvokeVoidAsync(this, "", "_initChart", nameof(ShowToast));
}
}

View File

@@ -96,6 +96,16 @@
</ValidateForm>
</Block>
<Block Title="禁用" Introduction="通过设置 <code>IsDisabled=true</code> 禁用">
<div class="form-inline">
<div class="row">
<div class="form-group col-12">
<CheckboxList @bind-Value="@Dummy.Name" IsDisabled="true" ShowBorder="false" Items="@Items2" />
</div>
</div>
</div>
</Block>
<AttributeTable Items="@GetAttributes()" />
<EventTable Items="@GetEvents()" />

View File

@@ -93,26 +93,30 @@ namespace BootstrapBlazor.Shared.Pages
private Foo Dummy { get; set; } = new Foo() { Name = "张三,李四" };
private static IEnumerable<AttributeItem> GetAttributes()
private static IEnumerable<AttributeItem> GetAttributes() => new AttributeItem[]
{
return new AttributeItem[]
{
new AttributeItem() {
Name = "Items",
Description = "数据源",
Type = "IEnumerable<SelectedItem>",
ValueList = " — ",
DefaultValue = " — "
},
new AttributeItem(){
Name = "Value",
Description = "组件值用于双向绑定",
Type = "TValue",
ValueList = " — ",
DefaultValue = " — "
}
};
}
new AttributeItem() {
Name = "Items",
Description = "数据源",
Type = "IEnumerable<SelectedItem>",
ValueList = "",
DefaultValue = " — "
},
new AttributeItem() {
Name = "IsDisabled",
Description = "是否禁用",
Type = "boolean",
ValueList = " — ",
DefaultValue = "false"
},
new AttributeItem(){
Name = "Value",
Description = "组件值用于双向绑定",
Type = "TValue",
ValueList = " — ",
DefaultValue = " — "
}
};
/// <summary>
/// 获得事件方法

View File

@@ -31,6 +31,31 @@
</div>
</Block>
<Block Title="颜色" Introduction="通过设置 <code>Color</code> 属性改变组件背景色">
<div class="form-inline">
<div class="row">
<div class="form-group col-12 col-md-4">
<Checkbox TValue="string" State="CheckboxState.Checked" DisplayText="选中" ShowLabel="true" Color="@Color.Primary"></Checkbox>
</div>
<div class="form-group col-12 col-md-4">
<Checkbox TValue="string" State="CheckboxState.Checked" DisplayText="选中" ShowLabel="true" Color="@Color.Success"></Checkbox>
</div>
<div class="form-group col-12 col-md-4">
<Checkbox TValue="string" State="CheckboxState.Checked" DisplayText="选中" ShowLabel="true" Color="@Color.Danger"></Checkbox>
</div>
<div class="form-group col-12 col-md-4">
<Checkbox TValue="string" State="CheckboxState.Checked" DisplayText="选中" ShowLabel="true" Color="@Color.Info"></Checkbox>
</div>
<div class="form-group col-12 col-md-4">
<Checkbox TValue="string" State="CheckboxState.Checked" DisplayText="选中" ShowLabel="true" Color="@Color.Warning"></Checkbox>
</div>
<div class="form-group col-12 col-md-4">
<Checkbox TValue="string" State="CheckboxState.Checked" DisplayText="选中" ShowLabel="true" Color="@Color.Dark"></Checkbox>
</div>
</div>
</div>
</Block>
<Block Title="Label 文字" Introduction="复选框显示文字,通过 <code>DisplayText</code> 设置组件显示文本,点击显示文字时组件状态也会进行翻转">
<p>设置<code>DisplayText</code> 属性,或者通过双向绑定均可以显示文本信息</p>
<div class="form-inline">

View File

@@ -5,7 +5,7 @@
<h4>通过折叠面板收纳内容区域</h4>
<Block Title="基础用法" Introduction="可同时展开多个面板,面板之间不影响">
<Collapse>
<Collapse OnCollapseChanged="@OnChanged">
<CollapseItems>
<CollapseItem Text="一致性 Consistency">
<div>与现实生活一致:与现实生活的流程、逻辑保持一致,遵循用户习惯的语言和概念;</div>
@@ -26,6 +26,7 @@
</CollapseItem>
</CollapseItems>
</Collapse>
<Logger @ref="Trace" class="mt-3" />
</Block>
<Block Title="指示箭头" Introduction="右侧显示指示箭头">
@@ -53,7 +54,7 @@
</Block>
<Block Title="手风琴效果" Introduction="每次只能展开一个面板">
<Collapse ShowArrow="true" IsAccordion ="true">
<Collapse ShowArrow="true" IsAccordion="true">
<CollapseItems>
<CollapseItem Text="一致性 Consistency">
<div>与现实生活一致:与现实生活的流程、逻辑保持一致,遵循用户习惯的语言和概念;</div>
@@ -76,4 +77,28 @@
</Collapse>
</Block>
<Block Title="子项标题颜色" Introduction="每个面板设置不同颜色">
<Collapse ShowArrow="true" IsAccordion="true">
<CollapseItems>
<CollapseItem Text="一致性 Consistency" TitleColor="Color.Primary">
<div>与现实生活一致:与现实生活的流程、逻辑保持一致,遵循用户习惯的语言和概念;</div>
<div>在界面中一致:所有的元素和结构需保持一致,比如:设计样式、图标和文本、元素的位置等。</div>
</CollapseItem>
<CollapseItem Text="反馈 Feedback" TitleColor="Color.Info">
<div>控制反馈:通过界面样式和交互动效让用户可以清晰的感知自己的操作;</div>
<div>页面反馈:操作后,通过页面元素的变化清晰地展现当前状态。</div>
</CollapseItem>
<CollapseItem Text="效率 Efficiency" TitleColor="Color.Success">
<div>简化流程:设计简洁直观的操作流程;</div>
<div>清晰明确:语言表达清晰且表意明确,让用户快速理解进而作出决策;</div>
<div>帮助用户识别:界面简单直白,让用户快速识别而非回忆,减少用户记忆负担。</div>
</CollapseItem>
<CollapseItem Text="可控 Controllability" TitleColor="Color.Warning">
<div>用户决策:根据场景可给予用户操作建议或安全提示,但不能代替用户进行决策;</div>
<div>结果可控:用户可以自由的进行操作,包括撤销、回退和终止当前操作等。</div>
</CollapseItem>
</CollapseItems>
</Collapse>
</Block>
<AttributeTable Items="@GetAttributes()" />

View File

@@ -2,10 +2,12 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Website: https://www.blazor.zone or https://argozhang.github.io/
using BootstrapBlazor.Components;
using BootstrapBlazor.Shared.Common;
using BootstrapBlazor.Shared.Pages.Components;
using Microsoft.AspNetCore.Components.Web;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
namespace BootstrapBlazor.Shared.Pages
{
@@ -14,18 +16,13 @@ namespace BootstrapBlazor.Shared.Pages
/// </summary>
public sealed partial class Collapses
{
/// <summary>
///
/// </summary>
[NotNull]
private Logger? Trace { get; set; }
/// <summary>
///
/// </summary>
/// <param name="e"></param>
private void ButtonClick(MouseEventArgs e)
private Task OnChanged(CollapseItem item)
{
Trace?.Log($"Button Clicked");
Trace.Log($"{item.Text}: {item.IsCollapsed}");
return Task.CompletedTask;
}
/// <summary>

View File

@@ -17,13 +17,9 @@ namespace BootstrapBlazor.Shared.Pages
/// </summary>
public sealed partial class Consoles : IDisposable
{
private readonly BlockingCollection<ConsoleMessageItem> _messages = new BlockingCollection<ConsoleMessageItem>(new ConcurrentQueue<ConsoleMessageItem>());
private readonly BlockingCollection<ConsoleMessageItem> _messages2 = new BlockingCollection<ConsoleMessageItem>(new ConcurrentQueue<ConsoleMessageItem>());
private readonly CancellationTokenSource _cancelTokenSource = new CancellationTokenSource();
private IEnumerable<ConsoleMessageItem> Messages => _messages;
private IEnumerable<ConsoleMessageItem> ColorMessages => _messages2;
private ConcurrentQueue<ConsoleMessageItem> Messages { get; set; } = new();
private ConcurrentQueue<ConsoleMessageItem> ColorMessages { get; set; } = new();
private readonly CancellationTokenSource _cancelTokenSource = new();
/// <summary>
///
@@ -38,23 +34,20 @@ namespace BootstrapBlazor.Shared.Pages
do
{
_locker.WaitOne();
if (!_messages.IsAddingCompleted)
Messages.Enqueue(new ConsoleMessageItem { Message = $"{DateTimeOffset.Now}: Dispatch Message" });
ColorMessages.Enqueue(new ConsoleMessageItem { Message = $"{DateTimeOffset.Now}: Dispatch Message", Color = GetColor() });
if (Messages.Count > 8)
{
_messages.Add(new ConsoleMessageItem { Message = $"{DateTimeOffset.Now}: Dispatch Message" });
_messages2.Add(new ConsoleMessageItem { Message = $"{DateTimeOffset.Now}: Dispatch Message", Color = GetColor() });
if (_messages.Count > 8)
{
_messages.TryTake(out var _);
}
if (_messages2.Count > 12)
{
_messages2.TryTake(out var _);
}
await InvokeAsync(StateHasChanged);
Messages.TryDequeue(out var _);
}
if (ColorMessages.Count > 12)
{
ColorMessages.TryDequeue(out var _);
}
await InvokeAsync(StateHasChanged);
_locker.Set();
await Task.Delay(2000, _cancelTokenSource.Token);
}
@@ -62,7 +55,7 @@ namespace BootstrapBlazor.Shared.Pages
});
}
private Color GetColor()
private static Color GetColor()
{
var second = DateTime.Now.Second;
return (second % 3) switch
@@ -73,22 +66,19 @@ namespace BootstrapBlazor.Shared.Pages
};
}
private readonly AutoResetEvent _locker = new AutoResetEvent(true);
private readonly AutoResetEvent _locker = new(true);
private void OnClear()
{
_locker.WaitOne();
if (!_messages.IsAddingCompleted)
while (!Messages.IsEmpty)
{
while (_messages.Count > 0)
{
_messages.TryTake(out var _);
}
Messages.TryDequeue(out var _);
}
_locker.Set();
}
private IEnumerable<AttributeItem> GetItemAttributes()
private static IEnumerable<AttributeItem> GetItemAttributes()
{
return new AttributeItem[]
{
@@ -113,7 +103,7 @@ namespace BootstrapBlazor.Shared.Pages
///
/// </summary>
/// <returns></returns>
private IEnumerable<AttributeItem> GetAttributes()
private static IEnumerable<AttributeItem> GetAttributes()
{
return new AttributeItem[]
{
@@ -187,7 +177,6 @@ namespace BootstrapBlazor.Shared.Pages
{
if (disposing)
{
_messages.CompleteAdding();
_cancelTokenSource.Cancel();
_cancelTokenSource.Dispose();
}

View File

@@ -4,23 +4,22 @@
<h4>通过注入服务调用 <code>Show</code> 方法弹出窗口进行人机交互</h4>
<Tips class="mt-3">
<p>
本组件使用注入服务的形式提供功能,使用时用户体验效果非常舒适,随时随地的调用,需要在使用本组件的页面中内置 <code>Dialog</code> 组件,或者在 <code>MainLayout</code> 主布局组件中内置,示例代码如下:
</p>
</Tips>
<Pre>&lt;Dialog /&gt;</Pre>
<Block Title="基本用法" Introduction="通过设置 <code>DialogOption</code> 属性对模态框进行基本属性设置">
<Button @onclick="@OnClick">点击打开 Dialog</Button>
</Block>
<Block Title="弹出复杂组件" Introduction="通过调用 <code>Show&lt;Counter&gt;()</code> 来弹出一个自定义组件">
<p>
本例中弹出对话框中包含一个示例网站的自带 <code>Counter</code> 组件,通过设置 <code>KeepChildrenState</code> 属性来控制弹窗内组件是否保持状态
<ul class="ul-demo">
<li>选择 <b>不保持状态</b> 时,弹窗内的计数器数据关闭弹窗后清零</li>
<li>选择 <b>保持状态</b> 时,弹窗内的计数器数据关闭弹窗后保持</li>
</ul>
本例中弹出对话框中包含一个示例网站的自带 <code>Counter</code> 组件
</p>
<p>
<Radio Items="@RadioItems" OnStateChanged="@OnStateChanged" />
</p>
<Button @onclick="@OnClickCounter">点击打开 Dialog</Button>
</Block>
@@ -64,16 +63,15 @@
</Block>
<Block Title="多级弹窗" Introduction="点击弹窗内部按钮继续弹出对话窗">
<Tips>
<div>通过嵌套调用注入的 <code>DialogService</code> 实例弹出对话窗,组件内部通过 <code>LIFO</code> 模式后弹先关的顺序对弹窗排序;通过此功能即可实现 <code>无限弹窗</code></div>
</Tips>
<div class="form-inline">
<div class="row">
<div class="col-12">
<Button OnClick="@ShowDialogLoop">弹窗</Button>
</div>
</div>
</div>
<p>功能介绍</p>
<ul class="ul-demo">
<li>点击按钮弹出对话窗</li>
<li>切换弹窗内 <code>Tab</code> 组件的第三个标签页 <b>角色管理</b></li>
<li>点击标签页中的弹窗继续弹出对话框</li>
<li>关闭当前对话框后之前打开的对话框 <b>保持状态</b></li>
</ul>
<Button OnClick="@ShowDialogLoop">弹窗</Button>
</Block>
<Block Title="模态对话框" Introduction="通过 <code>ShowModal</code> 方法弹出线程阻塞模式的对话框">
@@ -110,12 +108,4 @@
</div>
</Block>
<Tips class="mt-3">
<p>
本组件使用注入服务的形式提供功能,使用时用户体验效果非常舒适,随时随地的调用,需要在使用本组件的页面中内置 <code>Dialog</code> 组件,或者在 <code>MainLayout</code> 主布局组件中内置,示例代码如下:
</p>
</Tips>
<Pre>&lt;Dialog /&gt;</Pre>
<AttributeTable Items="@GetAttributes()" Title="DialogOption 属性" />

View File

@@ -15,36 +15,20 @@ using System.Threading.Tasks;
namespace BootstrapBlazor.Shared.Pages
{
/// <summary>
///
/// 弹窗组件示例代码
/// </summary>
public sealed partial class Dialogs
{
/// <summary>
///
/// </summary>
private IEnumerable<SelectedItem> RadioItems { get; set; } = new SelectedItem[] {
new SelectedItem("false", "不保持状态") { Active = true },
new SelectedItem("true", "保持状态")
};
[NotNull]
private Logger? Trace { get; set; }
/// <summary>
///
/// 获得 弹窗注入服务
/// </summary>
[Inject]
[NotNull]
private DialogService? DialogService { get; set; }
private Task OnStateChanged(CheckboxState state, SelectedItem item)
{
KeepState = bool.Parse(item.Value);
return Task.CompletedTask;
}
private bool KeepState { get; set; }
/// <summary>
///
/// </summary>
@@ -52,9 +36,9 @@ namespace BootstrapBlazor.Shared.Pages
private Task OnClick() => DialogService.Show(new DialogOption()
{
Title = "我是服务创建的弹出框",
BodyTemplate = DynamicComponent.CreateComponent<Button>(new KeyValuePair<string, object>[]
BodyTemplate = BootstrapDynamicComponent.CreateComponent<Button>(new[]
{
new KeyValuePair<string, object>(nameof(Button.ChildContent), new RenderFragment(builder => builder.AddContent(0, "我是服务创建的按钮")))
new KeyValuePair<string, object?>(nameof(Button.ChildContent), new RenderFragment(builder => builder.AddContent(0, "我是服务创建的按钮")))
})
.Render()
});
@@ -65,10 +49,10 @@ namespace BootstrapBlazor.Shared.Pages
{
Title = "利用代码关闭弹出框",
};
option.BodyTemplate = DynamicComponent.CreateComponent<Button>(new KeyValuePair<string, object>[]
option.BodyTemplate = BootstrapDynamicComponent.CreateComponent<Button>(new[]
{
new KeyValuePair<string, object>(nameof(Button.Text), "点击关闭弹窗"),
new KeyValuePair<string, object>(nameof(Button.OnClick), EventCallback.Factory.Create<MouseEventArgs>(this, async () => await option.Dialog.Close()))
new KeyValuePair<string, object?>(nameof(Button.Text), "点击关闭弹窗"),
new KeyValuePair<string, object?>(nameof(Button.OnClick), EventCallback.Factory.Create<MouseEventArgs>(this, async () => await option.Dialog.Close()))
}).Render();
await DialogService.Show(option);
}
@@ -80,8 +64,7 @@ namespace BootstrapBlazor.Shared.Pages
private Task OnClickCounter() => DialogService.Show(new DialogOption()
{
Title = "自带的 Counter 组件",
KeepChildrenState = KeepState,
Component = DynamicComponent.CreateComponent<Counter>()
Component = BootstrapDynamicComponent.CreateComponent<Counter>()
});
/// <summary>
@@ -110,9 +93,9 @@ namespace BootstrapBlazor.Shared.Pages
ShowFooter = false,
BodyContext = DataPrimaryId
};
op.BodyTemplate = DynamicComponent.CreateComponent<DataDialogComponent>(new List<KeyValuePair<string, object>>
op.BodyTemplate = BootstrapDynamicComponent.CreateComponent<DataDialogComponent>(new KeyValuePair<string, object?>[]
{
new KeyValuePair<string, object>(nameof(DataDialogComponent.OnClose), new Action(async () => await op.Dialog.Close()))
new(nameof(DataDialogComponent.OnClose), new Action(async () => await op.Dialog.Close()))
}).Render();
await DialogService.Show(op);
@@ -124,7 +107,7 @@ namespace BootstrapBlazor.Shared.Pages
var result = await DialogService.ShowModal<ResultDialogDemo>(new ResultDialogOption()
{
Title = "带返回值模态弹出框",
ComponentParamters = new KeyValuePair<string, object>[]
ComponentParamters = new KeyValuePair<string, object?>[]
{
new(nameof(ResultDialogDemo.Value), DemoValue1),
new(nameof(ResultDialogDemo.ValueChanged), EventCallback.Factory.Create<int>(this, v => DemoValue1 = v))
@@ -142,10 +125,10 @@ namespace BootstrapBlazor.Shared.Pages
var result = await DialogService.ShowModal<ResultDialogDemo2>(new ResultDialogOption()
{
Title = "选择收件人",
BodyContext = 10,
BodyContext = new ResultDialogDemo2.FooContext() { Count = 10, Emails = InputValue },
ButtonYesText = "选择",
ButtonYesIcon = "fa fa-search",
ComponentParamters = new KeyValuePair<string, object>[]
ComponentParamters = new KeyValuePair<string, object?>[]
{
// 用于初始化已选择的用户邮件
new(nameof(ResultDialogDemo2.Emails), Emails),
@@ -159,47 +142,12 @@ namespace BootstrapBlazor.Shared.Pages
}
}
private int _counter;
private async Task ShowDialogLoop()
{
await DialogService.Show(new DialogOption()
{
Title = $"弹窗 {_counter++}",
Component = DynamicComponent.CreateComponent<Button>(new KeyValuePair<string, object>[]
{
new KeyValuePair<string, object>(nameof(Button.Text), $"点击弹窗 {DateTime.Now:HH:mm:ss}"),
new KeyValuePair<string, object>(nameof(Button.OnClick), EventCallback.Factory.Create<MouseEventArgs>(this, async () => await ShowDialogLoop1()))
}),
OnCloseAsync = () =>
{
_counter--;
return Task.CompletedTask;
}
});
}
private async Task ShowDialogLoop1()
{
await DialogService.Show(new DialogOption()
{
Title = $"弹窗 {_counter++}",
BodyTemplate = builder =>
{
builder.OpenElement(0, "div");
builder.OpenComponent<Counter>(1);
builder.CloseComponent();
builder.AddContent(2, new MarkupString($"<div>当前时间 {DateTime.Now:HH:mm:ss}</div>"));
builder.OpenComponent<Button>(3);
builder.AddAttribute(4, nameof(Button.Text), $"点击弹窗 {DateTime.Now:HH:mm:ss}");
builder.AddAttribute(4, nameof(Button.OnClick), EventCallback.Factory.Create<MouseEventArgs>(this, async () => await ShowDialogLoop()));
builder.CloseComponent();
builder.CloseElement();
},
OnCloseAsync = () =>
{
_counter--;
return Task.CompletedTask;
}
Title = $"弹窗 {DateTime.Now}",
Component = BootstrapDynamicComponent.CreateComponent<DialogDemo>()
});
}
@@ -239,13 +187,6 @@ namespace BootstrapBlazor.Shared.Pages
ValueList = " — ",
DefaultValue = " — "
},
new AttributeItem() {
Name = "KeepChildrenState",
Description = "是否保持弹窗内组件状态",
Type = "boolean",
ValueList = "true|false",
DefaultValue = "false"
},
new AttributeItem() {
Name = "IsCentered",
Description = "是否垂直居中",

View File

@@ -0,0 +1,128 @@
@page "/displays"
<h3>Display 显示组件</h3>
<h4>显示静态文本数据</h4>
<Block Title="基础用法" Introduction="仅显示">
<div class="row">
<div class="col-auto col-form-label">
<span>基本用法</span>
</div>
<div class="col-6">
<Display TValue="string" Value="@Model.Name" />
</div>
</div>
</Block>
<Block Title="双向绑定数据" Introduction="通过双向绑定可以自动获取资源文件中的显示标签">
<p><code>Display</code> 组件开启双向绑定时,会根据绑定的 <code>Model</code> 属性值去自动获取 <code>Display/DisplayName</code> 标签值并且显示为前置 <code>Label</code>,通过 <code>DisplayText</code> 属性可以自定义显示前置标签,或者通过 <code>ShowLabel</code> 属性关闭前置标签是否显示</p>
<div class="form-inline">
<div class="row">
<Divider Text="自定义标签" />
<div class="form-group col-12">
<p>设置 <code>DisplayText</code> 值为 <b>自定义标签</b></p>
</div>
<div class="form-group col-12">
<Display @bind-Value="@Model.Name" DisplayText="自定义标签" ShowLabel="true" />
</div>
<Divider Text="占位" />
<div class="form-group col-12">
<p>无论是否设置 <code>DisplayText</code> 值,当 <code>ShowLabel</code> 为 <code>true</code> 时均显示</p>
</div>
<div class="form-group col-12">
<Display @bind-Value="@Model.Name" ShowLabel="true" />
</div>
<Divider Text="不占位" />
<div class="form-group col-12">
<p>无论是否设置 <code>DisplayText</code> 值,当 <code>ShowLabel</code> 为 <code>false</code> 时均不显示</p>
</div>
<div class="form-group col-12">
<Display @bind-Value="@Model.Name" />
</div>
</div>
</div>
</Block>
<Block Title="泛型绑定" Introduction="<code>Display</code> 组件内置对 <code>枚举</code> <code>集合</code> <code>数组</code> 进行处理,如不符合条件时,请自定义格式化或者回调委托方法">
<div class="form-inline">
<div class="row">
<div class="form-group col-12 col-sm-6">
<Display FormatString="000" @bind-Value="@Model.Count" ShowLabel="true" DisplayText="整型" />
</div>
<div class="form-group col-12 col-sm-6">
<Display @bind-Value="@Model.Education" ShowLabel="true" DisplayText="枚举" />
</div>
<div class="form-group col-12 col-sm-6">
<Display @bind-Value="@Model.Hobby" ShowLabel="true" DisplayText="集合" />
</div>
<div class="form-group col-12 col-sm-6">
<Display @bind-Value="@ByteArray" ShowLabel="true" DisplayText="数组" />
</div>
<div class="form-group col-12 col-sm-6">
<Display Value="@DateTime.Now" ShowLabel="true" DisplayText="DateTime" />
</div>
<div class="form-group col-12 col-sm-6">
<Display Value="@DateTimeOffset.Now" ShowLabel="true" DisplayText="DateTimeOffset" />
</div>
</div>
</div>
</Block>
<Block Title="表单内使用" Introduction="<code>Display</code> 组件在表单组件 <code>EditorForm</code> 中使用,多用于明细页,不可编辑模式">
<p><b><code>form-inline form-group</code></b> 模式</p>
<EditorForm Model="@Model" ItemsPerRow="3" IsDisplay="true">
<FieldItems>
<EditorItem @bind-Field="@Model.Hobby" Data="@Hobbys" />
</FieldItems>
</EditorForm>
<p><b><code>form-inline</code></b> 模式</p>
<div class="form-inline">
<div class="row">
<div class="col-12 col-sm-6"><Display @bind-Value="@Model.Count" ShowLabel="true" DisplayText="整型" /></div>
<div class="col-12 col-sm-6"><Display @bind-Value="@Model.Education" ShowLabel="true" DisplayText="枚举" /></div>
</div>
</div>
</Block>
<Block Title="自定义格式" Introduction="设置 <code>FormatString</code> 属性值为 <code>yyyy-MM-dd</code> 时,组件显示的时间格式为年月日">
<div class="form-inline">
<div class="row">
<div class="form-group col-12 col-sm-6">设置 <code class="ml-1">FormatString</code></div>
<div class="form-group col-12 col-sm-6">
<Display Value="DateTime.Now" FormatString="yyyy-MM-dd" />
</div>
<div class="form-group col-12 col-sm-6">设置 <code class="ml-1">Formatter</code></div>
<div class="form-group col-12 col-sm-6">
<Display Value="DateTime.Now" FormatterAsync="@DateTimeFormatter" />
</div>
</div>
</div>
<p class="mt-3"><code>Display</code> 组件绑定 <code>byte[]</code> 数组,格式化成 <code>base64</code> 编码字符串示例</p>
<div class="form-inline">
<div class="row">
<div class="form-group col-12 col-sm-6">设置 <code class="ml-1">Formatter</code></div>
<div class="form-group col-12 col-sm-6">
<Display Value="@ByteArray" FormatterAsync="@ByteArrayFormatter" />
</div>
</div>
</div>
</Block>
<Block Title="自动翻译为 Text" Introduction="设置 <code>Data</code> 值为 <code>IEnumerable&lt;SelectedItem&gt;</code> 集合,组件将通过此数据集,进行通过 <code>Value</code> 显示 <code>Text</code> 翻译工作">
<p>
<div>本例中组件 <code>Value="@@IntValue"</code> 设置 <code>Data="@@IntValueSource"</code> 组件将 <code>Value</code> 值对应的 <code>Text</code> 显示出来</div>
<div><b>InitValue</b>: 1,2,3</div>
<div><b>IntValueSource</b>: Text1,Text2,Text3</div>
</p>
<div class="form-inline">
<div class="row">
<div class="col-12 col-sm-6">
<Display Value="@IntValue" Data="@IntValueSource" />
</div>
</div>
</div>
</Block>
<AttributeTable Items="@GetAttributes()" />

View File

@@ -0,0 +1,96 @@
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Website: https://www.blazor.zone or https://argozhang.github.io/
using BootstrapBlazor.Components;
using BootstrapBlazor.Shared.Common;
using BootstrapBlazor.Shared.Pages.Components;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Localization;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading.Tasks;
namespace BootstrapBlazor.Shared.Pages
{
/// <summary>
/// Display 组件示例
/// </summary>
public partial class Displays
{
[NotNull]
private Foo? Model { get; set; }
[Inject]
[NotNull]
private IStringLocalizer<Foo>? Localizer { get; set; }
[NotNull]
private IEnumerable<SelectedItem>? Hobbys { get; set; }
private byte[] ByteArray { get; set; } = new byte[] { 0x01, 0x12, 0x34, 0x56 };
private IEnumerable<int> IntValue { get; set; } = new[] { 1, 2, 3 };
private IEnumerable<SelectedItem> IntValueSource { get; set; } = new[]
{
new SelectedItem("1", "Text1"),
new SelectedItem("2", "Text2"),
new SelectedItem("3", "Text3")
};
private static async Task<string> ByteArrayFormatter(byte[] source)
{
await Task.Delay(10);
return Convert.ToBase64String(source);
}
private static Task<string> DateTimeFormatter(DateTime source) => Task.FromResult(source.ToString("yyyy-MM-dd"));
/// <summary>
/// OnInitialized 方法
/// </summary>
protected override void OnInitialized()
{
base.OnInitialized();
Model = Foo.Generate(Localizer);
Model.Hobby = Foo.GenerateHobbys(Localizer).Take(3).Select(i => i.Text);
Hobbys = Foo.GenerateHobbys(Localizer);
}
private static IEnumerable<AttributeItem> GetAttributes() => new[]
{
new AttributeItem() {
Name = "ShowLabel",
Description = "是否显示前置标签",
Type = "bool",
ValueList = "true|false",
DefaultValue = "false"
},
new AttributeItem() {
Name = "DisplayText",
Description = "前置标签显示文本",
Type = "string",
ValueList = " — ",
DefaultValue = " — "
},
new AttributeItem() {
Name = "FormatString",
Description = "数值格式化字符串",
Type = "string",
ValueList = " — ",
DefaultValue = " — "
},
new AttributeItem() {
Name = "Formatter",
Description = "TableHeader 实例",
Type = "RenderFragment<TItem>",
ValueList = " — ",
DefaultValue = " — "
}
};
}
}

View File

@@ -0,0 +1,57 @@
@page "/downloads"
<h3>Download 文件下载</h3>
<h4>用于直接下载物理文件</h4>
<Tips>
<p>
本组件使用注入服务的形式提供功能,使用时用户体验效果非常舒适,随时随地的调用,需要在使用本组件的页面中内置 <code>Download</code> 组件,或者在 <code>MainLayout</code> 主布局组件中内置,示例代码如下:
</p>
</Tips>
<Pre>&lt;Download /&gt;</Pre>
<Block Title="基本用法" Introduction="调用注入服务 <code>DownloadService</code>">
<p>
<b>特别注意:</b>
<div>
<code>Blazor</code> 与 <code>js</code> 的交互使用了 <code>json</code>,在 <code>ssr</code> 模式中,<code>json</code> 最大传输大小是 <b>125M</b>,这是 <code>asp.net core</code> 的限制。并且由于 <code>json</code> 转 <code>js</code> 的 <code>blob</code> 非常非常慢,所以大文件请谨慎,建议只在类似页面文件导出、报表图片下载等页面自行完成的内容中使用。
其他例如服务器文件下载等依旧使用 <code>Controller</code> 来完成。如果下载大文件请自行仔细测试
</div>
</p>
<div class="mb-3">
示例:
<Button Icon="fa fa-download" Text="下载文件" OnClick="@DownloadFileAsync"></Button>
</div>
<div><code>Razor</code> 代码</div>
<Pre>&lt;Button OnClick=&quot;DownloadFile&quot;&gt;点我下载文件&lt;/Button&gt;</Pre>
<div><code>C#</code> 代码</div>
<Pre>private async Task DownloadFileAsync()
{
var content = await GenerateFileAsync();
await downloadService.DownloadAsync("测试文件", content);
static async Task&lt;byte[]&gt; GenerateFileAsync()
{
using var ms = new MemoryStream();
using var writer = new StreamWriter(ms);
await writer.WriteLineAsync("自行生成并写入的文本,这里可以换成图片或其他内容");
await writer.FlushAsync();
ms.Position = 0;
return ms.ToArray();
}
}</Pre>
</Block>
<Block Title="大文件下载测试" Introduction="这里模拟生成了一个 <code>100万行</code> 的文本文件,大概 <b>56M</b>,可以自行测试">
<p>按钮设置 <code>IsAsync</code> 值为 <code>true</code> 进行异步下载操作</p>
<Button IsAsync="true" Icon="fa fa-download" Text="大文件下载" OnClickWithoutRender="DownloadLargeFileAsync"></Button>
</Block>
<Block Title="获取图片并显示" Introduction="模拟直接由前端页面生成验证码或者上传图片不保存直接显示的情况。">
<p>由于测试使用了wwwroot下的文件没有代码生成wasm无法访问wwwroot文件夹故此测试只有ssr模式可用。wasm请自行测试。</p>
<img src="@TempUrl" style="width: 120px; height: auto;" />
</Block>
<Download></Download>

View File

@@ -0,0 +1,93 @@
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Website: https://www.blazor.zone or https://argozhang.github.io/
using BootstrapBlazor.Components;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Options;
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Threading.Tasks;
namespace BootstrapBlazor.Shared.Pages
{
/// <summary>
/// Title 网站标题示例代码
/// </summary>
public partial class Downloads
{
[Inject]
[NotNull]
private ToastService? ToastService { get; set; }
[Inject]
[NotNull]
private DownloadService? downloadService { get; set; }
[Inject]
[NotNull]
private IOptions<WebsiteOptions>? SiteOptions { get; set; }
private string? TempUrl { get; set; }
/// <summary>
/// 渲染完成事件
/// </summary>
/// <param name="firstRender"></param>
/// <returns></returns>
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await base.OnAfterRenderAsync(firstRender);
if (firstRender)
{
if (OperatingSystem.IsBrowser())
{
await ToastService.Information("显示图片", "当前模式为 WebAssembly 模式,无法直接调用 wwwroot 文件夹,请自行生成图片测试。");
}
else
{
var filePath = Path.Combine(SiteOptions.Value.WebRootPath, "favicon.png");
TempUrl = await downloadService.CreateUrlAsync("favicon.png", File.OpenRead(filePath),
"image/jpeg");
StateHasChanged();
}
}
}
private async Task DownloadFileAsync()
{
var content = await GenerateFileAsync();
await downloadService.DownloadAsync("测试文件.txt", content);
static async Task<byte[]> GenerateFileAsync()
{
using var ms = new MemoryStream();
using var writer = new StreamWriter(ms);
await writer.WriteLineAsync("自行生成并写入的文本,这里可以换成图片或其他内容");
await writer.FlushAsync();
ms.Position = 0;
return ms.ToArray();
}
}
private Task DownloadLargeFileAsync() => Task.Run(async () =>
{
using var stream = await GenerateFileStreamAsync();
await downloadService.DownloadAsync("测试大文件.txt", stream);
static async Task<Stream> GenerateFileStreamAsync()
{
var ms = new MemoryStream();
var writer = new StreamWriter(ms);
for (var i = 0; i < 1000; i++)
{
await writer.WriteLineAsync($"这里是一个大文件下载示例共循环100万次");
}
await writer.FlushAsync();
ms.Position = 0;
return ms;
}
});
}
}

View File

@@ -22,11 +22,8 @@
<EditorItem @bind-Field="@Model.Complete" Editable="false" />
<EditorItem @bind-Field="@Model.Hobby">
<EditTemplate Context="value">
@{
var model = value as Foo;
}
<div class="form-group col-12">
<CheckboxList @bind-Value="@model!.Hobby" Items="@Hobbys" />
<CheckboxList @bind-Value="@Model.Hobby" Items="@Hobbys" />
</div>
</EditTemplate>
</EditorItem>
@@ -45,21 +42,11 @@
<ValidateForm Model="@ValidateModel">
<EditorForm TModel="Foo">
<FieldItems>
<EditorItem @bind-Field="@Model.DateTime" Readonly="true" />
<EditorItem @bind-Field="@Model.Hobby">
<EditorItem @bind-Field="@ValidateModel.DateTime" Readonly="true" />
<EditorItem @bind-Field="@ValidateModel.Hobby">
<EditTemplate Context="value">
@{
var model = value as Foo;
}
<div class="form-group col-12">
<CheckboxList @bind-Value="@model!.Hobby" Items="@Hobbys" />
</div>
</EditTemplate>
</EditorItem>
<EditorItem @bind-Field="@Model.Complete">
<EditTemplate Context="value">
<div class="form-group col-6">
<Switch @bind-Value="((Foo)value).Complete" />
<CheckboxList @bind-Value="@ValidateModel.Hobby" Items="@Hobbys" />
</div>
</EditTemplate>
</EditorItem>
@@ -121,7 +108,7 @@
<EditorItem @bind-Field="@Model.Hobby" Data="@Hobbys" />
</FieldItems>
<Buttons>
<Button Icon="fa fa-save" Text="提交" />
<Button ButtonType="ButtonType.Submit" Icon="fa fa-save" Text="提交" />
</Buttons>
</EditorForm>
</ValidateForm>

View File

@@ -114,17 +114,17 @@
</div>
<div class="form-group col-12 col-sm-6">
<div class="demo-inputnumber">
<BootstrapInputNumber Value="10" Color="Color.Danger" />
<BootstrapInputNumber Value="@BindFloatValue" Color="Color.Danger" FormatString="#.##" />
</div>
</div>
<div class="form-group col-12 col-sm-6">
<div class="demo-inputnumber">
<BootstrapInputNumber Value="10" Color="Color.Dark" />
<BootstrapInputNumber Value="@BindDoubleValue" Color="Color.Dark" FormatString="#.##" />
</div>
</div>
<div class="form-group col-12 col-sm-6">
<div class="demo-inputnumber">
<BootstrapInputNumber Value="10" Color="Color.Secondary" />
<BootstrapInputNumber Value="@BindDecimalValue" Color="Color.Secondary" FormatString="#.##" />
</div>
</div>
</div>
@@ -139,16 +139,6 @@
<BootstrapInputNumber Value="@BindShortValue" DisplayText="Short" ShowLabel="true" ShowButton="true" />
</div>
</div>
<div class="form-group col-12 col-sm-6">
<div class="demo-inputnumber">
<BootstrapInputNumber Value="@BindLongValue" DisplayText="Long" ShowLabel="true" ShowButton="true" />
</div>
</div>
<div class="form-group col-12 col-sm-6">
<div class="demo-inputnumber">
<BootstrapInputNumber Value="@BindFloatValue" DisplayText="Float" ShowLabel="true" ShowButton="true" />
</div>
</div>
<div class="form-group col-12 col-sm-6">
<div class="demo-inputnumber">
<BootstrapInputNumber Value="@BindValue" DisplayText="Int" ShowLabel="true" ShowButton="true" />
@@ -156,12 +146,22 @@
</div>
<div class="form-group col-12 col-sm-6">
<div class="demo-inputnumber">
<BootstrapInputNumber Value="@BindDoubleValue" DisplayText="Double" ShowLabel="true" ShowButton="true" />
<BootstrapInputNumber Value="@BindLongValue" DisplayText="Long" ShowLabel="true" ShowButton="true" />
</div>
</div>
<div class="form-group col-12 col-sm-6">
<div class="demo-inputnumber">
<BootstrapInputNumber Value="@BindDecimalValue" DisplayText="Decimal" ShowLabel="true" ShowButton="true" />
<BootstrapInputNumber Value="@BindFloatValue" DisplayText="Float" ShowLabel="true" ShowButton="true" FormatString="#.##" />
</div>
</div>
<div class="form-group col-12 col-sm-6">
<div class="demo-inputnumber">
<BootstrapInputNumber Value="@BindDoubleValue" DisplayText="Double" ShowLabel="true" ShowButton="true" FormatString="#.##" />
</div>
</div>
<div class="form-group col-12 col-sm-6">
<div class="demo-inputnumber">
<BootstrapInputNumber Value="@BindDecimalValue" DisplayText="Decimal" ShowLabel="true" ShowButton="true" FormatString="#.##" />
</div>
</div>
</div>

View File

@@ -29,7 +29,6 @@
<Block Title="双向绑定数据" Introduction="绑定组件内变量,数据自动同步">
<p><code>BootstrapInput</code> 组件开启双向绑定时,会根据绑定的 <code>Model</code> 属性值去自动获取 <code>Display/DisplayName</code> 标签值并且显示为前置 <code>Label</code>,通过 <code>DisplayText</code> 属性可以自定义显示前置标签,或者通过 <code>ShowLabel</code> 属性关闭前置标签是否显示</p>
<Tips>特别注意:所有表单组件如果内置到 <code>EditForm</code> 中使用时,即使 <code>ShowLabel</code> 设置为 <code>false</code> 也是会显示前置标签</Tips>
<div class="form-inline">
<div class="row">
<Divider Text="自定义标签" />

View File

@@ -34,62 +34,59 @@ namespace BootstrapBlazor.Shared.Pages
PlaceHolderText = Localizer["PlaceHolder"];
}
private static IEnumerable<AttributeItem> GetAttributes()
private static IEnumerable<AttributeItem> GetAttributes() => new[]
{
return new AttributeItem[]
new AttributeItem() {
Name = "ChildContent",
Description = "验证控件",
Type = "RenderFragment",
ValueList = " — ",
DefaultValue = " — "
},
new AttributeItem() {
Name = "ShowLabel",
Description = "是否显示前置标签",
Type = "bool",
ValueList = "true|false",
DefaultValue = "false"
},
new AttributeItem() {
Name = "DisplayText",
Description = "前置标签显示文本",
Type = "string",
ValueList = " — ",
DefaultValue = " — "
},
new AttributeItem() {
Name = "FormatString",
Description = "数值格式化字符串",
Type = "string",
ValueList = " — ",
DefaultValue = " — "
},
new AttributeItem() {
Name = "Formatter",
Description = "TableHeader 实例",
Type = "RenderFragment<TItem>",
ValueList = " — ",
DefaultValue = " — "
},
new AttributeItem()
{
new AttributeItem() {
Name = "ChildContent",
Description = "验证控件",
Type = "RenderFragment",
ValueList = " — ",
DefaultValue = " — "
},
new AttributeItem() {
Name = "ShowLabel",
Description = "是否显示前置标签",
Type = "bool",
ValueList = "true|false",
DefaultValue = "false"
},
new AttributeItem() {
Name = "DisplayText",
Description = "前置标签显示文本",
Type = "string",
ValueList = " — ",
DefaultValue = " — "
},
new AttributeItem() {
Name = "FormatString",
Description = "数值格式化字符串",
Type = "string",
ValueList = " — ",
DefaultValue = " — "
},
new AttributeItem() {
Name = "Formatter",
Description = "TableHeader 实例",
Type = "RenderFragment<TItem>",
ValueList = " — ",
DefaultValue = " — "
},
new AttributeItem()
{
Name = "type",
Description = "控件类型",
Type = "string",
ValueList = "text / number / email / url / password",
DefaultValue = "text"
},
new AttributeItem()
{
Name = "IsDisabled",
Description = "是否禁用 默认为 fasle",
Type = "bool",
ValueList = "true|false",
DefaultValue = "false"
}
};
}
Name = "type",
Description = "控件类型",
Type = "string",
ValueList = "text / number / email / url / password",
DefaultValue = "text"
},
new AttributeItem()
{
Name = "IsDisabled",
Description = "是否禁用 默认为 fasle",
Type = "bool",
ValueList = "true|false",
DefaultValue = "false"
}
};
}
}

View File

@@ -0,0 +1,152 @@
@layout ComponentLayout
@page "/labels"
<h3>组件标签</h3>
<p>本套组件中有 <code>ValidateForm</code> <code>EditorForm</code> 以及多种继承 <code>ValidateBase&lt;TValue&gt;</code> 的 <b>表单组件</b>,这些组件中有一套特殊的显示前置标签逻辑,现在我们统一的梳理一下:</p>
<ul class="ul-demo">
<li><a href="/validateforms" target="_blank">ValidateForm</a> 组件是 <b>可验证的</b> 表单组件,此组件内的表单组件会自动进行数据合规性检查,如果数据不合规将会阻止 <b>提交(Submit)</b> 动作,是数据提交中使用最最最频繁的组件</li>
<li><a href="/editorforms" target="_blank">EditorForm</a> 组件是普通的表单组件,此组件绑定 <code>Model</code> 后即可自动生成整个表单,大大减少重复性编码,外面套上 <code>ValidateForm</code> 即可开启 <b>数据合规性检查</b> 非常方便、简洁、高效</li>
</ul>
<p>以 <a href="/inputs" target="_blank">BootstrapInput</a> 输入框组件为例,阐述一下是否显示 <code>Label</code> 逻辑</p>
<Tips>
<p><code>ShowLabel</code> 的逻辑即就近原则,离自身越近的设置生效,如表单组件内置到 <code>ValidateForm</code> 组件中,即使 <code>ValidateForm</code> 设置 <code>ShowLabel=true</code>,表单组件自身设置 <code>ShowLabel=false</code> 时,标签最终结果为 <b>不显示</b></p>
</Tips>
<Block Title="单独使用" Introduction="适用于数据录入">
<p><b>未使用双向绑定时</b></p>
<ul class="ul-demo">
<li>默认不会显示 <code>Label</code></li>
<li>通过 <code>ShowLabel</code> 属性进行控制是否显示</li>
<li>设置 <code>DisplayText</code> 时显示内容</li>
<li>未设置时渲染一个无内容的 <code>label</code> 组件进行占位</li>
</ul>
<GroupBox Title="未双向绑定" style="margin-top: 1.5rem;">
<div>第一个文本框未进行任何设置,不显示标签</div>
<div>第二个文本框设置 <code>ShowLabel="true" DisplayText=""</code> 显示无内容的占位标签</div>
<div>第三个文本框设置 <code>ShowLabel="true" DisplayText="Name"</code> 显示设置的内容标签</div>
<div>第四个文本框设置 <code>ShowLabel="true" DisplayText="@@null"</code> 显示无内容的占位标签</div>
<div class="form-inline mt-3">
<div class="form-row">
<div class="form-group col-sm-12 col-md-3">
<BootstrapInput TValue="string" />
</div>
<div class="form-group col-sm-12 col-md-3">
<BootstrapInput TValue="string" ShowLabel="true" DisplayText="" />
</div>
<div class="form-group col-sm-12 col-md-3">
<BootstrapInput TValue="string" ShowLabel="true" DisplayText="@Localizer[nameof(Foo.Name)]" />
</div>
<div class="form-group col-sm-12 col-md-3">
<BootstrapInput TValue="string" ShowLabel="true" DisplayText="@null" />
</div>
</div>
</div>
</GroupBox>
<p class="mt-3"><b>使用双向绑定时</b></p>
<GroupBox Title="双向绑定" class="mt-3">
<div>第一个文本框设置 <code>@@bind-Value="@@Dummy.Name"</code>,不显示标签</div>
<div>第二个文本框设置 <code>@@bind-Value="@@Dummy.Name" ShowLabel="true" DisplayText="@@Localizer[nameof(Foo.Address)]"</code> 显示设置的内容</div>
<div>第三个文本框设置 <code>@@bind-Value="@@Dummy.Name" ShowLabel="true" DisplayText=""</code> 显示无内容占位标签</div>
<div>第四个文本框设置 <code>@@bind-Value="@@Dummy.Name" ShowLabel="true" DisplayText="@@null"</code> 显示资源文件机制下的标签内容 <code>Label</code></div>
<div class="form-inline mt-3">
<div class="form-row">
<div class="form-group col-sm-12 col-md-3">
<BootstrapInput @bind-Value="@Dummy.Name" />
</div>
<div class="form-group col-sm-12 col-md-3">
<BootstrapInput @bind-Value="@Dummy.Name" ShowLabel="true" DisplayText="@Localizer[nameof(Foo.Address)]" />
</div>
<div class="form-group col-sm-12 col-md-3">
<BootstrapInput @bind-Value="@Dummy.Name" ShowLabel="true" DisplayText="" />
</div>
<div class="form-group col-sm-12 col-md-3">
<BootstrapInput @bind-Value="@Dummy.Name" ShowLabel="true" DisplayText="@null" />
</div>
</div>
</div>
</GroupBox>
</Block>
<Block Title="EditorForm 中使用" , Introduction="未套 <code>ValidateForm</code> 中使用">
<p><b>显示标签</b><div>未设置 <coe>EditorForm</coe> 组件的 <code>ShowLabel</code> 属性,未设置时等同于设置为 <code>true</code>,所有组件 <b>显示</b> 标签</div></p>
<GroupBox>
<EditorForm Model="@Dummy">
<FieldItems>
<EditorItem @bind-Field="@context.Hobby" Data="@Foo.GenerateHobbys(Localizer)">
</EditorItem>
</FieldItems>
</EditorForm>
</GroupBox>
<p class="mt-3"><b>不显示标签</b><div>设置 <code>ShowLabel="false"</code>,组件内的所有表单组件 <b>不显示</b> 标签</div></p>
<GroupBox>
<EditorForm Model="@Dummy" ShowLabel="false">
<FieldItems>
<EditorItem @bind-Field="@context.Hobby" Data="@Foo.GenerateHobbys(Localizer)">
</EditorItem>
</FieldItems>
</EditorForm>
</GroupBox>
</Block>
<Block Title="EditorForm 内置 ValidateForm 中使用" , Introduction="外置 <code>ValidateForm</code> 中使用">
<p><b>显示标签</b><div>未设置 <coe>EditorForm</coe> 组件的 <code>ShowLabel</code> 属性,未设置时等同于设置为 <code>true</code>,所有组件 <b>显示</b> 标签</div></p>
<GroupBox>
<ValidateForm Model="@Dummy">
<EditorForm TModel="Foo">
<FieldItems>
<EditorItem @bind-Field="@context.Hobby" Data="@Foo.GenerateHobbys(Localizer)">
</EditorItem>
</FieldItems>
</EditorForm>
</ValidateForm>
</GroupBox>
<p class="mt-3"><b>不显示标签</b><div>设置 <code>ShowLabel="false"</code>,组件内的所有表单组件 <b>不显示</b> 标签</div></p>
<GroupBox>
<ValidateForm Model="@Dummy" ShowLabel="false">
<EditorForm TModel="Foo">
<FieldItems>
<EditorItem @bind-Field="@context.Hobby" Data="@Foo.GenerateHobbys(Localizer)">
</EditorItem>
</FieldItems>
</EditorForm>
</ValidateForm>
</GroupBox>
</Block>
<Block Title="ValidateForm 中使用" , Introduction="默认自动开启显示标签">
<p><b>显示标签</b><div>未设置 <coe>EditorForm</coe> 组件的 <code>ShowLabel</code> 属性,未设置时等同于设置为 <code>true</code>,所有组件 <b>显示</b> 标签</div></p>
<GroupBox>
<ValidateForm Model="@Dummy" class="form-inline">
<div class="form-row">
<div class="form-group col-sm-12 col-md-6">
<BootstrapInput @bind-Value="@Dummy.Name" />
</div>
<div class="form-group col-sm-12 col-md-6">
<BootstrapInput @bind-Value="@Dummy.Address" />
</div>
</div>
</ValidateForm>
</GroupBox>
<p class="mt-3"><b>不显示标签</b><div>设置 <code>ShowLabel="false"</code>,组件内的所有表单组件 <b>不显示</b> 标签</div></p>
<GroupBox>
<ValidateForm Model="@Dummy" ShowLabel="false" class="form-inline">
<div class="form-row">
<div class="form-group col-sm-12 col-md-6">
<BootstrapInput @bind-Value="@Dummy.Name" />
</div>
<div class="form-group col-sm-12 col-md-6">
<BootstrapInput @bind-Value="@Dummy.Address" />
</div>
</div>
</ValidateForm>
</GroupBox>
</Block>

View File

@@ -0,0 +1,34 @@
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Website: https://www.blazor.zone or https://argozhang.github.io/
using BootstrapBlazor.Shared.Pages.Components;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Localization;
using System.Diagnostics.CodeAnalysis;
namespace BootstrapBlazor.Shared.Pages
{
/// <summary>
///
/// </summary>
public partial class Labels : ComponentBase
{
[Inject]
[NotNull]
private IStringLocalizer<Foo>? Localizer { get; set; }
[NotNull]
private Foo? Dummy { get; set; }
/// <summary>
/// OnInitialized 方法
/// </summary>
protected override void OnInitialized()
{
base.OnInitialized();
Dummy = Foo.Generate(Localizer);
}
}
}

View File

@@ -98,7 +98,7 @@ namespace BootstrapBlazor.Shared.Pages
/// <returns></returns>
public async Task UpdateAsync()
{
await RootPage.SetParametersAsync(ParameterView.FromDictionary(new Dictionary<string, object>()
await RootPage.SetParametersAsync(ParameterView.FromDictionary(new Dictionary<string, object?>()
{
[nameof(RootPage.IsFullSide)] = IsFullSide,
[nameof(RootPage.IsFixedFooter)] = IsFixedFooter && ShowFooter,

View File

@@ -125,7 +125,7 @@
</Header>
<Side>
<div style="position: absolute; top: 0; left:0; right: 0; bottom: 0; overflow: auto; border-right: 1px solid rgba(0,0,0,.125); padding: 6px 0;">
<Menu Items="@GetIconSideMenuItems()" IsVertical="true"></Menu>
<Menu Items="@IconSideMenuItems" DisableNavigation="true" IsVertical="true"></Menu>
</div>
</Side>
<Main>
@@ -146,7 +146,7 @@
</Header>
<Side>
<div style="border-right: 1px solid rgba(0,0,0,.125); padding: 6px 0;">
<Menu Items="@GetIconSideMenuItems()" IsVertical="true"></Menu>
<Menu Items="@IconSideMenuItems" DisableNavigation="true" IsVertical="true"></Menu>
</div>
</Side>
<Main>

View File

@@ -4,7 +4,12 @@
using BootstrapBlazor.Components;
using BootstrapBlazor.Shared.Common;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Localization;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
using static BootstrapBlazor.Shared.Pages.Menus;
namespace BootstrapBlazor.Shared.Pages
{
@@ -13,31 +18,24 @@ namespace BootstrapBlazor.Shared.Pages
/// </summary>
public sealed partial class Layouts
{
[Inject]
[NotNull]
private IStringLocalizer<Menus>? Localizer { get; set; }
private IEnumerable<MenuItem> GetIconSideMenuItems()
private IEnumerable<MenuItem>? IconSideMenuItems { get; set; }
/// <summary>
/// OnInitializedAsync 方法
/// </summary>
/// <returns></returns>
protected override async Task OnInitializedAsync()
{
var ret = new List<MenuItem>
{
new MenuItem() { Text = "系统设置", IsActive = true, Icon = "fa fa-fw fa-gears" },
new MenuItem() { Text = "权限设置", Icon = "fa fa-fw fa-users" },
new MenuItem() { Text = "日志设置", Icon = "fa fa-fw fa-database" }
};
await base.OnInitializedAsync();
ret[0].AddItem(new MenuItem() { Text = "网站设置", Icon = "fa fa-fw fa-fa" });
ret[0].AddItem(new MenuItem() { Text = "任务设置", Icon = "fa fa-fw fa-tasks" });
ret[1].AddItem(new MenuItem() { Text = "用户设置", Icon = "fa fa-fw fa-user" });
ret[1].AddItem(new MenuItem() { Text = "菜单设置", Icon = "fa fa-fw fa-dashboard" });
ret[1].AddItem(new MenuItem() { Text = "角色设置", Icon = "fa fa-fw fa-sitemap" });
ret[2].AddItem(new MenuItem() { Text = "访问日志", Icon = "fa fa-fw fa-bars" });
ret[2].AddItem(new MenuItem() { Text = "登录日志", Icon = "fa fa-fw fa-user-circle-o" });
ret[2].AddItem(new MenuItem() { Text = "操作日志", Icon = "fa fa-fw fa-edit" });
return ret;
IconSideMenuItems = await MenusDataGerator.GetIconSideMenuItemsAsync(Localizer);
}
private IEnumerable<AttributeItem> GetAttributes() => new AttributeItem[]
private static IEnumerable<AttributeItem> GetAttributes() => new AttributeItem[]
{
// TODO: 移动到数据库中
new AttributeItem() {

View File

@@ -57,4 +57,9 @@
<Markdown Height="500" MinHeight="300" Placeholder="这是 Markdown" PreviewStyle="PreviewStyle.Tab" InitialEditType="InitialEditType.Wysiwyg" Language="@Language"></Markdown>
</Block>
<Block Title="浏览器模式" Introduction="单纯浏览模式,不可编辑">
<p>设置<code>Markdown</code> 编辑器为纯浏览模式,<code>IsViewer="true"</code></p>
<Markdown IsViewer="true" Value="# Viewer Mode"></Markdown>
</Block>
<AttributeTable Items="GetAttributes()"></AttributeTable>

View File

@@ -18,8 +18,6 @@ namespace BootstrapBlazor.Shared.Pages
private string? HtmlString { get; set; }
private string ShowHideButtonString { get; set; } = "隐藏 Editor";
/// <summary>
/// 获得/设置 版本号字符串
/// </summary>
@@ -81,6 +79,13 @@ namespace BootstrapBlazor.Shared.Pages
Type = "string",
ValueList = " — ",
DefaultValue = " — "
},
new AttributeItem(){
Name = "IsViewer",
Description = "是否为纯浏览模式",
Type = "bool",
ValueList = " true/false ",
DefaultValue = " false "
}
};
}

View File

@@ -19,8 +19,8 @@
</Block>
<Block Title="侧栏" Introduction="适用于左右结构布局的网站,通过设置 <code>IsVertical</code> 更改导航菜单为侧栏">
<div style="width:220px;">
<Menu Items="@SideMenuItems" DisableNavigation="true" IsVertical="true" OnClick="@OnClickSideMenu" style="border-right: 1px solid #e6e6e6;" />
<div style="width:220px; border-right: 1px solid #e6e6e6; padding-right: 4px;">
<Menu Items="@SideMenuItems" DisableNavigation="true" IsVertical="true" OnClick="@OnClickSideMenu" />
</div>
<Logger @ref="TraceSideMenu" class="mt-3" />
</Block>
@@ -51,7 +51,7 @@
</Header>
<Side>
<div class="menu-demo" style="background-color: #2f4050; color: #dcdfe6; height: 100%; padding: 6px 0;">
<Menu Items="@IconSideMenuItems" IsVertical="true" IsCollapsed="@IsCollapsed" />
<Menu Items="@IconSideMenuItems" DisableNavigation="true" IsVertical="true" IsCollapsed="@IsCollapsed" />
</div>
</Side>
<Main>
@@ -76,13 +76,22 @@
</div>
</Block>
<Block Title="动态更改菜单" Introduction="通过代码动态设置 <code>Items</code> 属性值更改菜单项">
<div class="mt-3" style="width:220px;">
<Menu Items="@DynamicSideMenuItems" DisableNavigation="true" IsVertical="true" style="border-right: 1px solid #e6e6e6;" />
</div>
<Button Text="更新菜单" OnClick="UpdateMenu" />
<Button Text="重置菜单" OnClick="ResetMenu" />
</Block>
<Block Title="部分菜单禁用功能" Introduction="通过设置 <code>MenuItem</code> 的 <code>IsDisabled</code> 属性设置节点是否禁用">
<p>本例中 <b>导航二</b> 节点为禁用状态,菜单与其子菜单均不可点击</p>
<Menu Items="@DisabledMenuItems" />
<Menu Items="@DisabledMenuItems" DisableNavigation="true" OnClick="@OnClick2" />
<p class="mt-3"><b>侧栏的禁用示例</b></p>
<div style="width:220px;">
<Menu Items="@DisabledMenuItems" DisableNavigation="true" IsVertical="true" style="border-right: 1px solid #e6e6e6;" />
<div style="width:220px; border-right: 1px solid #e6e6e6;">
<Menu Items="@DisabledMenuItems" DisableNavigation="true" IsVertical="true" OnClick="@OnClick2" />
</div>
<Logger @ref="Trace2" class="mt-3" />
</Block>
<AttributeTable Items="@GetAttributes()" />

View File

@@ -6,8 +6,9 @@ using BootstrapBlazor.Components;
using BootstrapBlazor.Shared.Common;
using BootstrapBlazor.Shared.Pages.Components;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Localization;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
namespace BootstrapBlazor.Shared.Pages
@@ -17,21 +18,54 @@ namespace BootstrapBlazor.Shared.Pages
/// </summary>
public sealed partial class Menus
{
/// <summary>
///
/// </summary>
[NotNull]
private Logger? Trace { get; set; }
[NotNull]
private Logger? Trace2 { get; set; }
[NotNull]
private Logger? TraceSideMenu { get; set; }
[NotNull]
private IEnumerable<MenuItem>? Items { get; set; }
[NotNull]
private IEnumerable<MenuItem>? IconItems { get; set; }
[NotNull]
private IEnumerable<MenuItem>? SideMenuItems { get; set; }
[NotNull]
private IEnumerable<MenuItem>? IconSideMenuItems { get; set; }
[NotNull]
private IEnumerable<MenuItem>? WidgetIconSideMenuItems { get; set; }
[NotNull]
private IEnumerable<MenuItem>? CollapsedIconSideMenuItems { get; set; }
[NotNull]
private IEnumerable<MenuItem>? DisabledMenuItems { get; set; }
[NotNull]
private IEnumerable<MenuItem>? DynamicSideMenuItems { get; set; }
[Inject]
[NotNull]
private IStringLocalizer<Menus>? Localizer { get; set; }
private Task OnClickMenu(MenuItem item)
{
Trace?.Log($"菜单点击项: {item.Text}");
Trace.Log($"菜单点击项: {item.Text}");
return Task.CompletedTask;
}
/// <summary>
///
/// </summary>
private Logger? TraceSideMenu { get; set; }
private Task OnClick2(MenuItem item)
{
Trace2.Log($"菜单点击项: {item.Text}");
return Task.CompletedTask;
}
private Task OnClickSideMenu(MenuItem item)
{
@@ -51,269 +85,344 @@ namespace BootstrapBlazor.Shared.Pages
return Task.CompletedTask;
}
private IEnumerable<MenuItem> Items { get; set; } = Enumerable.Empty<MenuItem>();
private IEnumerable<MenuItem> GetItems()
/// <summary>
/// OnInitialized 方法
/// </summary>
protected override async Task OnInitializedAsync()
{
var ret = new List<MenuItem>
{
new MenuItem() { Text = "导航一" },
new MenuItem() { Text = "导航二", IsActive = true },
new MenuItem() { Text = "导航三" }
};
ret[1].AddItem(new MenuItem() { Text = "子菜单一" });
ret[1].AddItem(new MenuItem() { Text = "子菜单二" });
ret[1].AddItem(new MenuItem() { Text = "子菜单三" });
ret[1].Items.ElementAt(0).AddItem(new MenuItem() { Text = "孙菜单1一" });
ret[1].Items.ElementAt(0).AddItem(new MenuItem() { Text = "孙菜单1二" });
ret[1].Items.ElementAt(1).AddItem(new MenuItem() { Text = "孙菜单2一" });
ret[1].Items.ElementAt(1).AddItem(new MenuItem() { Text = "孙菜单2二" });
ret[1].Items.ElementAt(1).Items.ElementAt(1).AddItem(new MenuItem() { Text = "曾孙菜单一" });
ret[1].Items.ElementAt(1).Items.ElementAt(1).AddItem(new MenuItem() { Text = "曾孙菜单二" });
ret[1].Items.ElementAt(1).Items.ElementAt(1).Items.ElementAt(1).AddItem(new MenuItem() { Text = "曾曾孙菜单一" });
ret[1].Items.ElementAt(1).Items.ElementAt(1).Items.ElementAt(1).AddItem(new MenuItem() { Text = "曾曾孙菜单二" });
return ret;
await base.OnInitializedAsync();
Items = await MenusDataGerator.GetTopItemsAsync(Localizer);
IconItems = await MenusDataGerator.GetTopIconItemsAsync(Localizer);
SideMenuItems = await MenusDataGerator.GetSideMenuItemsAsync(Localizer);
IconSideMenuItems = await MenusDataGerator.GetIconSideMenuItemsAsync(Localizer);
WidgetIconSideMenuItems = await MenusDataGerator.GetWidgetIconSideMenuItemsAsync(Localizer);
CollapsedIconSideMenuItems = await MenusDataGerator.GetCollapsedIconSideMenuItemsAsync(Localizer);
DisabledMenuItems = await MenusDataGerator.GetDisabledMenuItemsAsync(Localizer);
DynamicSideMenuItems = await MenusDataGerator.GetSideMenuItemsAsync(Localizer);
}
private IEnumerable<MenuItem> IconItems { get; set; } = Enumerable.Empty<MenuItem>();
private IEnumerable<MenuItem> GetIconItems()
private async Task UpdateMenu()
{
var ret = new List<MenuItem>
{
new MenuItem() { Text = "导航一", Icon = "fa fa-life-bouy fa-fw" },
new MenuItem() { Text = "导航二", Icon = "fa fa-fa fa-fw", IsActive = true },
new MenuItem() { Text = "导航三", Icon = "fa fa-rebel fa-fw" }
};
ret[1].AddItem(new MenuItem() { Text = "子菜单一", Icon = "fa fa-fa fa-fw" });
ret[1].AddItem(new MenuItem() { Text = "子菜单二", Icon = "fa fa-fa fa-fw" });
ret[1].AddItem(new MenuItem() { Text = "子菜单三", Icon = "fa fa-fa fa-fw" });
return ret;
DynamicSideMenuItems = await MenusDataGerator.GetIconSideMenuItemsAsync(Localizer);
}
private IEnumerable<MenuItem> SideMenuItems { get; set; } = Enumerable.Empty<MenuItem>();
private IEnumerable<MenuItem> GetSideMenuItems()
private async Task ResetMenu()
{
var ret = new List<MenuItem>
{
new MenuItem() { Text = "导航一" },
new MenuItem() { Text = "导航二" },
new MenuItem() { Text = "导航三" },
new MenuItem() { Text = "导航四" }
};
ret[1].AddItem(new MenuItem() { Text = "子菜单一" });
ret[1].AddItem(new MenuItem() { Text = "子菜单二" });
ret[1].AddItem(new MenuItem() { Text = "子菜单三" });
ret[3].AddItem(new MenuItem() { Text = "子菜单一" });
ret[3].AddItem(new MenuItem() { Text = "子菜单二" });
ret[3].AddItem(new MenuItem() { Text = "子菜单三" });
ret[1].Items.ElementAt(0).AddItem(new MenuItem() { Text = "孙菜单1一" });
ret[1].Items.ElementAt(0).AddItem(new MenuItem() { Text = "孙菜单1二" });
ret[1].Items.ElementAt(1).AddItem(new MenuItem() { Text = "孙菜单2一" });
ret[1].Items.ElementAt(1).AddItem(new MenuItem() { Text = "孙菜单2二" });
ret[1].Items.ElementAt(0).Items.ElementAt(0).AddItem(new MenuItem() { Text = "曾孙菜单一" });
ret[1].Items.ElementAt(0).Items.ElementAt(0).AddItem(new MenuItem() { Text = "曾孙菜单二" });
ret[1].Items.ElementAt(0).Items.ElementAt(0).Items.ElementAt(0).AddItem(new MenuItem() { Text = "曾曾孙菜单一" });
ret[1].Items.ElementAt(0).Items.ElementAt(0).Items.ElementAt(0).AddItem(new MenuItem() { Text = "曾曾孙菜单二" });
return ret;
DynamicSideMenuItems = await MenusDataGerator.GetSideMenuItemsAsync(Localizer);
}
private IEnumerable<MenuItem> IconSideMenuItems { get; set; } = Enumerable.Empty<MenuItem>();
private IEnumerable<MenuItem> GetIconSideMenuItems()
private static IEnumerable<AttributeItem> GetAttributes() => new AttributeItem[]
{
var ret = new List<MenuItem>
new AttributeItem()
{
new MenuItem() { Text = "系统设置", IsActive = true, Icon = "fa fa-fw fa-gears" },
new MenuItem() { Text = "权限设置", Icon = "fa fa-fw fa-users" },
new MenuItem() { Text = "日志设置", Icon = "fa fa-fw fa-database" }
};
Name = "Items",
Description = "菜单组件数据集合",
Type = "IEnumerable<MenuItem>",
ValueList = " — ",
DefaultValue = " — "
},
new AttributeItem()
{
Name = "IsVertical",
Description = "是否为侧栏",
Type = "bool",
ValueList = "true|false",
DefaultValue = "false"
},
new AttributeItem() {
Name = "IsAccordion",
Description = "是否手风琴效果",
Type = "bool",
ValueList = "true|false",
DefaultValue = "false"
},
new AttributeItem() {
Name = "DisableNavigation",
Description = "是否禁止地址栏导航",
Type = "bool",
ValueList = "true|false",
DefaultValue = "false"
},
new AttributeItem() {
Name = "OnClick",
Description = "菜单项被点击时回调此方法",
Type = "Func<MenuItem, Task>",
ValueList = " — ",
DefaultValue = " — "
}
};
ret[0].AddItem(new MenuItem() { Text = "网站设置", Icon = "fa fa-fw fa-fa" });
ret[0].AddItem(new MenuItem() { Text = "任务设置", Icon = "fa fa-fw fa-tasks" });
ret[1].AddItem(new MenuItem() { Text = "用户设置", Icon = "fa fa-fw fa-user" });
ret[1].AddItem(new MenuItem() { Text = "菜单设置", Icon = "fa fa-fw fa-dashboard" });
ret[1].AddItem(new MenuItem() { Text = "角色设置", Icon = "fa fa-fw fa-sitemap" });
ret[2].AddItem(new MenuItem() { Text = "访问日志", Icon = "fa fa-fw fa-bars" });
ret[2].AddItem(new MenuItem() { Text = "登录日志", Icon = "fa fa-fw fa-user-circle-o" });
ret[2].AddItem(new MenuItem() { Text = "操作日志", Icon = "fa fa-fw fa-edit" });
return ret;
}
private DynamicComponent BuildDynamicComponent()
internal static class MenusDataGerator
{
return DynamicComponent.CreateComponent<Badge>(new KeyValuePair<string, object>[]
public static async Task<IEnumerable<MenuItem>> GetTopItemsAsync(IStringLocalizer localizer)
{
new KeyValuePair<string, object>(nameof(Badge.Color), Color.Danger),
new KeyValuePair<string, object>(nameof(Badge.IsPill), true),
new KeyValuePair<string, object>(nameof(Badge.ChildContent), new RenderFragment(builder =>
await Task.Delay(1);
return new List<MenuItem>
{
new(localizer["Menu1"].Value),
new(localizer["Menu2"].Value)
{
IsActive = true,
Items = new List<MenuItem>
{
new(localizer["SubMenu1"].Value)
{
Items = new List<MenuItem>
{
new(localizer["SubMenu11"].Value),
new(localizer["SubMenu12"].Value)
}
},
new(localizer["SubMenu2"].Value)
{
Items = new List<MenuItem>
{
new(localizer["SubMenu21"].Value),
new(localizer["SubMenu22"].Value)
{
Items = new List<MenuItem>
{
new(localizer["SubMenu31"].Value),
new(localizer["SubMenu32"].Value)
{
Items = new List<MenuItem>
{
new(localizer["SubMenu41"].Value),
new(localizer["SubMenu42"].Value)
}
}
}
}
}
},
new(localizer["SubMenu3"].Value)
}
},
new(localizer["Menu3"].Value)
};
}
public static async Task<IEnumerable<MenuItem>> GetTopIconItemsAsync(IStringLocalizer localizer)
{
await Task.Delay(1);
return new List<MenuItem>
{
new(localizer["Menu1"].Value, icon:"fa fa-life-bouy"),
new(localizer["Menu2"].Value, icon:"fa fa-fa")
{
IsActive = true,
Items = new List<MenuItem>
{
new(localizer["SubMenu1"].Value, icon:"fa fa-fa"),
new(localizer["SubMenu2"].Value, icon:"fa fa-fa"),
new(localizer["SubMenu3"].Value, icon:"fa fa-fa"),
}
},
new(localizer["Menu3"].Value, icon:"fa fa-rebel fa-fw")
};
}
public static async Task<IEnumerable<MenuItem>> GetSideMenuItemsAsync(IStringLocalizer localizer)
{
await Task.Delay(1);
return new List<MenuItem>
{
new(localizer["Menu1"].Value, icon: "fa fa-fa"),
new(localizer["Menu2"].Value)
{
IsActive = true,
Items = new List<MenuItem>
{
new(localizer["SubMenu1"].Value)
{
Items = new List<MenuItem>
{
new(localizer["SubMenu11"].Value),
new(localizer["SubMenu12"].Value)
}
},
new(localizer["SubMenu2"].Value)
{
Items = new List<MenuItem>
{
new(localizer["SubMenu21"].Value),
new(localizer["SubMenu22"].Value)
{
Items = new List<MenuItem>
{
new(localizer["SubMenu31"].Value),
new(localizer["SubMenu32"].Value)
{
Items = new List<MenuItem>
{
new(localizer["SubMenu41"].Value),
new(localizer["SubMenu42"].Value)
}
}
}
}
}
},
new(localizer["SubMenu3"].Value)
}
},
new(localizer["Menu3"].Value)
};
}
public static async Task<IEnumerable<MenuItem>> GetDisabledMenuItemsAsync(IStringLocalizer localizer)
{
await Task.Delay(1);
return new List<MenuItem>
{
new(localizer["Menu1"].Value)
{
IsActive = true,
Items = new List<MenuItem>
{
new(localizer["SubMenu1"].Value)
}
},
new(localizer["Menu2"].Value)
{
IsDisabled = true,
Items = new List<MenuItem>
{
new(localizer["SubMenu2"].Value)
}
},
new(localizer["Menu3"].Value)
{
Items = new List<MenuItem>
{
new(localizer["SubMenu3"].Value)
}
}
};
}
private static BootstrapDynamicComponent BuildDynamicComponent() => BootstrapDynamicComponent.CreateComponent<Badge>(new[]
{
new KeyValuePair<string, object?>(nameof(Badge.Color), Color.Danger),
new KeyValuePair<string, object?>(nameof(Badge.IsPill), true),
new KeyValuePair<string, object?>(nameof(Badge.ChildContent), new RenderFragment(builder =>
{
var index = 0;
builder.AddContent(index++, "10");
}))
});
}
private IEnumerable<MenuItem> WidgetIconSideMenuItems { get; set; } = Enumerable.Empty<MenuItem>();
private IEnumerable<MenuItem> GetWidgetIconSideMenuItems()
{
var ret = new List<MenuItem>
public static async Task<IEnumerable<MenuItem>> GetIconSideMenuItemsAsync(IStringLocalizer localizer)
{
new MenuItem() { Text = "系统设置", Icon = "fa fa-fw fa-gears" },
new MenuItem() { Text = "权限设置", Icon = "fa fa-fw fa-users" },
new MenuItem() {
Text = "日志设置",
IsActive = true,
Icon = "fa fa-fw fa-database",
Component = BuildDynamicComponent()
}
};
ret[0].AddItem(new MenuItem() { Text = "网站设置", Icon = "fa fa-fw fa-fa" });
ret[0].AddItem(new MenuItem() { Text = "任务设置", Icon = "fa fa-fw fa-tasks" });
ret[1].AddItem(new MenuItem() { Text = "用户设置", Icon = "fa fa-fw fa-user" });
ret[1].AddItem(new MenuItem() { Text = "菜单设置", Icon = "fa fa-fw fa-dashboard" });
ret[1].AddItem(new MenuItem() { Text = "角色设置", Icon = "fa fa-fw fa-sitemap" });
ret[2].AddItem(new MenuItem() { Text = "访问日志", Icon = "fa fa-fw fa-bars" });
ret[2].AddItem(new MenuItem() { Text = "登录日志", Icon = "fa fa-fw fa-user-circle-o" });
ret[2].AddItem(new MenuItem()
{
Text = "操作日志",
Icon = "fa fa-fw fa-edit",
Component = BuildDynamicComponent()
});
return ret;
}
private IEnumerable<MenuItem> CollapsedIconSideMenuItems { get; set; } = Enumerable.Empty<MenuItem>();
private IEnumerable<MenuItem> GetCollapsedIconSideMenuItems()
{
var ret = new List<MenuItem>
{
new MenuItem() { Text = "系统设置", Icon = "fa fa-fw fa-gears" },
new MenuItem() { Text = "权限设置", IsActive = true, Icon = "fa fa-fw fa-users" , IsCollapsed = false },
new MenuItem() { Text = "日志设置", Icon = "fa fa-fw fa-database" }
};
ret[0].AddItem(new MenuItem() { Text = "网站设置", Icon = "fa fa-fw fa-fa" });
ret[0].AddItem(new MenuItem() { Text = "任务设置", Icon = "fa fa-fw fa-tasks" });
ret[1].AddItem(new MenuItem() { Text = "用户设置", Icon = "fa fa-fw fa-user" });
ret[1].AddItem(new MenuItem() { Text = "菜单设置", Icon = "fa fa-fw fa-dashboard" });
ret[1].AddItem(new MenuItem() { Text = "角色设置", Icon = "fa fa-fw fa-sitemap" });
ret[2].AddItem(new MenuItem() { Text = "访问日志", Icon = "fa fa-fw fa-bars" });
ret[2].AddItem(new MenuItem() { Text = "登录日志", Icon = "fa fa-fw fa-user-circle-o" });
ret[2].AddItem(new MenuItem() { Text = "操作日志", Icon = "fa fa-fw fa-edit" });
return ret;
}
private IEnumerable<MenuItem> DisabledMenuItems { get; set; } = Enumerable.Empty<MenuItem>();
private IEnumerable<MenuItem> GetDisabledMenuItems()
{
var ret = new List<MenuItem>
{
new MenuItem() { Text = "导航一", IsActive = true },
new MenuItem() { Text = "导航二", IsDisabled = true },
new MenuItem() { Text = "导航三" },
new MenuItem() { Text = "导航四", IsDisabled = true },
};
ret[1].AddItem(new MenuItem() { Text = "子菜单一", Icon = "fa fa-fa fa-fw" });
ret[2].AddItem(new MenuItem() { Text = "子菜单二", Icon = "fa fa-fa fa-fw" });
ret[2].AddItem(new MenuItem() { Text = "子菜单三", Icon = "fa fa-fa fa-fw", IsDisabled = true });
return ret;
}
/// <summary>
/// OnInitialized 方法
/// </summary>
protected override void OnInitialized()
{
base.OnInitialized();
Items = GetItems();
IconItems = GetIconItems();
SideMenuItems = GetSideMenuItems();
IconSideMenuItems = GetIconSideMenuItems();
WidgetIconSideMenuItems = GetWidgetIconSideMenuItems();
CollapsedIconSideMenuItems = GetCollapsedIconSideMenuItems();
DisabledMenuItems = GetDisabledMenuItems();
}
/// <summary>
///
/// </summary>
/// <returns></returns>
private IEnumerable<AttributeItem> GetAttributes()
{
return new AttributeItem[]
{
new AttributeItem()
await Task.Delay(1);
return new List<MenuItem>
{
Name = "Items",
Description = "菜单组件数据集合",
Type = "IEnumerable<MenuItem>",
ValueList = " — ",
DefaultValue = " — "
},
new AttributeItem()
new(localizer["System"].Value, icon: "fa fa-gears")
{
IsActive = true,
Items = new List<MenuItem>
{
new(localizer["Website"].Value, icon: "fa fa-fa"),
new(localizer["Task"].Value, icon: "fa fa-tasks")
}
},
new(localizer["Authorize"].Value, icon: "fa fa-users")
{
Items = new List<MenuItem>
{
new(localizer["User"].Value, icon: "fa fa-user"),
new(localizer["Menu"].Value, icon: "fa fa-dashboard"),
new(localizer["Role"].Value, icon: "fa fa-sitemap")
}
},
new(localizer["Log"].Value, icon: "fa fa-database")
{
Items = new List<MenuItem>
{
new(localizer["Access"].Value, icon: "fa fa-bars"),
new(localizer["Login"].Value, icon: "fa fa-user-circle-o"),
new(localizer["Operation"].Value, icon: "fa fa-edit")
}
}
};
}
public static async Task<IEnumerable<MenuItem>> GetWidgetIconSideMenuItemsAsync(IStringLocalizer localizer)
{
await Task.Delay(1);
return new List<MenuItem>
{
Name = "IsVertical",
Description = "是否为侧栏",
Type = "bool",
ValueList = "true|false",
DefaultValue = "false"
},
new AttributeItem() {
Name = "IsAccordion",
Description = "是否手风琴效果",
Type = "bool",
ValueList = "true|false",
DefaultValue = "false"
},
new AttributeItem() {
Name = "DisableNavigation",
Description = "是否禁止地址栏导航",
Type = "bool",
ValueList = "true|false",
DefaultValue = "false"
},
new AttributeItem() {
Name = "OnClick",
Description = "菜单项被点击时回调此方法",
Type = "Func<MenuItem, Task>",
ValueList = " — ",
DefaultValue = " — "
}
};
new(localizer["System"].Value, icon: "fa fa-gears")
{
IsActive = true,
Items = new List<MenuItem>
{
new(localizer["Website"].Value, icon: "fa fa-fa"),
new(localizer["Task"].Value, icon: "fa fa-tasks")
}
},
new(localizer["Authorize"].Value, icon: "fa fa-users")
{
Items = new List<MenuItem>
{
new(localizer["User"].Value, icon: "fa fa-user"),
new(localizer["Menu"].Value, icon: "fa fa-dashboard"),
new(localizer["Role"].Value, icon: "fa fa-sitemap")
}
},
new(localizer["Log"].Value, icon: "fa fa-database")
{
Component = BuildDynamicComponent(),
Items = new List<MenuItem>
{
new(localizer["Access"].Value, icon: "fa fa-bars"),
new(localizer["Login"].Value, icon: "fa fa-user-circle-o"),
new(localizer["Operation"].Value, icon: "fa fa-edit")
{
Component = BuildDynamicComponent()
}
}
}
};
}
public static async Task<IEnumerable<MenuItem>> GetCollapsedIconSideMenuItemsAsync(IStringLocalizer localizer)
{
await Task.Delay(1);
return new List<MenuItem>
{
new(localizer["System"].Value, icon: "fa fa-gears")
{
IsActive = true,
Items = new List<MenuItem>
{
new(localizer["Website"].Value, icon: "fa fa-fa"),
new(localizer["Task"].Value, icon: "fa fa-tasks")
}
},
new(localizer["Authorize"].Value, icon: "fa fa-users")
{
IsCollapsed = false,
Items = new List<MenuItem>
{
new(localizer["User"].Value, icon: "fa fa-user"),
new(localizer["Menu"].Value, icon: "fa fa-dashboard"),
new(localizer["Role"].Value, icon: "fa fa-sitemap")
}
},
new(localizer["Log"].Value, icon: "fa fa-database")
{
Items = new List<MenuItem>
{
new(localizer["Access"].Value, icon: "fa fa-bars"),
new(localizer["Login"].Value, icon: "fa fa-user-circle-o"),
new(localizer["Operation"].Value, icon: "fa fa-edit")
}
}
};
}
}
}
}

View File

@@ -8,43 +8,45 @@
<div class="form-inline">
<div class="row">
<div class="form-group col-12 col-sm-6">
<MultiSelect TValue="string" Items="@Items"></MultiSelect>
<MultiSelect TValue="string" Items="@Items" @bind-Value="@Model.Address"></MultiSelect>
</div>
<div class="form-group col-12 col-sm-6">
<MultiSelect TValue="string" Color="Color.Primary" Items="@Items"></MultiSelect>
<MultiSelect TValue="string" Color="Color.Primary" Items="@Items" @bind-Value="@Model.Address"></MultiSelect>
</div>
<div class="form-group col-12 col-sm-6">
<MultiSelect TValue="string" Color="Color.Success" Items="@Items"></MultiSelect>
<MultiSelect TValue="string" Color="Color.Success" Items="@Items" @bind-Value="@Model.Address"></MultiSelect>
</div>
<div class="form-group col-12 col-sm-6">
<MultiSelect TValue="string" Color="Color.Danger" Items="@Items"></MultiSelect>
<MultiSelect TValue="string" Color="Color.Danger" Items="@Items" @bind-Value="@Model.Address"></MultiSelect>
</div>
<div class="form-group col-12 col-sm-6">
<MultiSelect TValue="string" Color="Color.Warning" Items="@Items"></MultiSelect>
<MultiSelect TValue="string" Color="Color.Warning" Items="@Items" @bind-Value="@Model.Address"></MultiSelect>
</div>
<div class="form-group col-12 col-sm-6">
<MultiSelect TValue="string" Color="Color.Info" Items="@Items"></MultiSelect>
<MultiSelect TValue="string" Color="Color.Info" Items="@Items" @bind-Value="@Model.Address"></MultiSelect>
</div>
<div class="form-group col-12 col-sm-6">
<MultiSelect TValue="string" Color="Color.Secondary" Items="@Items"></MultiSelect>
<MultiSelect TValue="string" Color="Color.Secondary" Items="@Items" @bind-Value="@Model.Address"></MultiSelect>
</div>
<div class="form-group col-12 col-sm-6">
<MultiSelect TValue="string" Color="Color.Dark" Items="@Items"></MultiSelect>
<MultiSelect TValue="string" Color="Color.Dark" Items="@Items" @bind-Value="@Model.Address"></MultiSelect>
</div>
</div>
</div>
</Block>
<Block Title="双向绑定值字符串" Introduction="绑定一个逗号字符串分割的字符串">
<p>本例中通过双向绑定 <code>SelectedItemsValue</code> 变量,通过下拉框选择更改其值</p>
<p>
<div><code>MutltiSelect</code> 组件数据源 <code>Items</code> 与 <b>选中值</b> <code>SelectedItemsValue</code> 均支持双向绑定;本例中通过双向绑定 <code>SelectedItemsValue</code> 变量,通过下拉框选择更改其值</div>
</p>
<div class="form-inline">
<div class="row">
<div class="form-group col-12 col-sm-6">
<MultiSelect Items="@Items" @bind-Value="@SelectedItemsValue"></MultiSelect>
<MultiSelect Items="@Items4" @bind-Value="@SelectedItemsValue"></MultiSelect>
</div>
<div class="form-group col-12 col-sm-6">
<Button Icon="fa fa-plus" Text="添加" OnClick="@AddItems" class="mr-1"></Button>
<Button Icon="fa fa-minus" Text="减少" OnClick="@RemoveItems"></Button>
<Button Icon="fa fa-plus" Text="添加选项" OnClick="@AddItems" class="mr-1"></Button>
<Button Icon="fa fa-minus" Text="减少选项" OnClick="@RemoveItems"></Button>
</div>
</div>
</div>
@@ -56,7 +58,7 @@
<div class="form-inline">
<div class="row">
<div class="form-group col-12 col-sm-6">
<MultiSelect Items="@Items" @bind-Value="@SelectedArrayValues"></MultiSelect>
<MultiSelect Items="@Items5" @bind-Value="@SelectedArrayValues"></MultiSelect>
</div>
<div class="form-group col-12 col-sm-6">
<Button Icon="fa fa-plus" Text="添加" OnClick="@AddListItems" class="mr-1"></Button>
@@ -84,11 +86,11 @@
</Block>
<Block Title="双向绑定枚举集合" Introduction="绑定一个泛型 <code>IEnumerable<Enum></code> 集合">
<p>本例中通过双向绑定 <code>SelectedEnumValues</code> 集合变量,通过下拉框选择更改其值</p>
<p>本例中通过双向绑定 <code>SelectedEnumValues</code> 集合变量,通过下拉框选择更改其值<b>枚举</b> 类型时无需设置 <code>Items</code> 参数,额外功能是组件内部会尝试查找资源文件或者 <code>DisplayAttribute</code> 与 <code>DescriptionAttribute</code> 标签尝试进行本地化翻译工作,如本例切换到 <b>中文</b> 时枚举值为 <b>小学</b> 与 <b>中学</b></p>
<div class="form-inline">
<div class="row">
<div class="form-group col-12 col-sm-6">
<MultiSelect @bind-Value="@SelectedEnumValues"></MultiSelect>
<MultiSelect @bind-Value="@SelectedEnumValues"></MultiSelect>
</div>
</div>
</div>
@@ -100,11 +102,11 @@
<div class="form-inline">
<div class="row">
<div class="form-group col-12 col-sm-6">
<MultiSelect Items="@Items" @bind-Value="@SelectedItemsValue" ShowSearch="true" OnSearchTextChanged="@OnSearch"></MultiSelect>
<MultiSelect Items="@Items6" @bind-Value="@SelectedItemsValue6" ShowSearch="true" OnSearchTextChanged="@OnSearch"></MultiSelect>
</div>
</div>
</div>
<div>@SelectedItemsValue</div>
<div>@SelectedItemsValue6</div>
<Logger @ref="Trace" class="mt-3" />
</Block>
@@ -113,23 +115,21 @@
<div class="form-inline">
<div class="row">
<div class="form-group col-12 col-sm-6">
<MultiSelect Items="@Items" @bind-Value="@SelectedItemsValue" IsDisabled="true" />
<MultiSelect Items="@Items7" Value="@SelectedItemsValue7" IsDisabled="true" />
</div>
</div>
</div>
<div>@SelectedItemsValue</div>
<Logger @ref="Trace" class="mt-3" />
</Block>
<Block Title="选项改变时事件" Introduction="通过设置 <code>IsDisabled</code> 值设置组件禁用状态">
<Block Title="选项改变时事件" Introduction="通过设置 <code>OnSelectedItemsChanged</code> 回调方法获取当前选中数据集合改变事件">
<div class="form-inline">
<div class="row">
<div class="form-group col-12 col-sm-6">
<MultiSelect Items="@Items" @bind-Value="@SelectedItemsValue" OnSelectedItemsChanged="@OnSelectedItemsChanged" />
<MultiSelect Items="@Items8" OnSelectedItemsChanged="@OnSelectedItemsChanged8" Value="@SelectedItemsValue8" />
</div>
</div>
</div>
<Logger @ref="Trace" />
<Logger @ref="Trace2" />
</Block>
<Block Title="客户端验证" Introduction="下拉框未选择时,点击提交按钮时拦截。">
@@ -152,7 +152,7 @@
<ValidateForm class="form-inline" Model="@Foo">
<div class="row">
<div class="form-group col-12">
<MultiSelect Color="Color.Primary" Items="@Items" @bind-Value="@Foo.Name" />
<MultiSelect Color="Color.Primary" Items="@Items9" @bind-Value="@Foo.Name" />
</div>
</div>
</ValidateForm>
@@ -160,7 +160,7 @@
<div class="form-inline">
<div class="row">
<div class="form-group col-12">
<MultiSelect Color="Color.Primary" Items="@Items" @bind-Value="@Foo.Name" />
<MultiSelect Color="Color.Primary" Items="@Items10" @bind-Value="@Foo.Name" />
</div>
</div>
</div>
@@ -168,7 +168,7 @@
<div class="form-inline">
<div class="row">
<div class="form-group col-12">
<MultiSelect Color="Color.Primary" Items="@Items" @bind-Value="@Foo.Name" DisplayText="自定义姓名" ShowLabel="true" />
<MultiSelect Color="Color.Primary" Items="@Items11" @bind-Value="@Foo.Name" DisplayText="自定义姓名" ShowLabel="true" />
</div>
</div>
</div>
@@ -176,30 +176,30 @@
<Block Title="选项超长文字" Introduction="候选项文字特别长">
<div style="max-width: 400px">
<MultiSelect Items="@LongItems" @bind-Value="@SelectedLongItemsValue" DisplayText="超长文字" ShowLabel="true"></MultiSelect>
<MultiSelect Items="@LongItems1" @bind-Value="@SelectedLongItemsValue1" DisplayText="超长文字" ShowLabel="true"></MultiSelect>
</div>
</Block>
<Block Title="全选与反选按钮" Introduction="通过设置 <code>ShowSelectAllButton</code> 值设置组件显示全选与反选按钮">
<div style="max-width: 400px">
<MultiSelect Items="@LongItems" @bind-Value="@SelectedLongItemsValue" ShowToolbar="true" ShowSearch="true"></MultiSelect>
<MultiSelect Items="@LongItems2" @bind-Value="@SelectedLongItemsValue2" ShowToolbar="true" ShowSearch="true"></MultiSelect>
</div>
</Block>
<Block Title="设置选项最大数与最小数" Introduction="通过设置 <code>Max</code> <code>Min</code> 值设置组件可选项数量限制">
<div style="max-width: 300px">
<p>最多可选择两个选项</p>
<MultiSelect Items="@LongItems" @bind-Value="@SelectedMaxItemsValue" Max="2"></MultiSelect>
<MultiSelect Items="@LongItems3" @bind-Value="@SelectedMaxItemsValue" Max="2"></MultiSelect>
</div>
<div style="max-width: 300px" class="mt-3">
<p>最少选择两个选项</p>
<MultiSelect Items="@LongItems" @bind-Value="@SelectedMinItemsValue" Min="2"></MultiSelect>
<MultiSelect Items="@LongItems4" @bind-Value="@SelectedMinItemsValue" Min="2"></MultiSelect>
</div>
</Block>
<Block Title="扩展工具栏按钮" Introduction="通过设置 <code>ButtonTemplate</code> 自定义工具栏按钮实现自定义功能">
<div style="max-width: 300px">
<MultiSelect Items="@LongItems" @bind-Value="@SelectedLongItemsValue" ShowToolbar="true" ShowDefaultButtons="false">
<MultiSelect Items="@LongItems5" @bind-Value="@SelectedLongItemsValue3" ShowToolbar="true" ShowDefaultButtons="false">
<ButtonTemplate>
<button class="btn" @onclick="@OnClickButton">测试</button>
</ButtonTemplate>
@@ -207,6 +207,20 @@
</div>
</Block>
<Block Title="级联绑定" Introduction="通过选择第一个下拉框不同选项,第二个下拉框动态填充内容。">
<p>本例中点击第一个下拉框,可以通过异步方法获取第二个多选框的数据源,进行赋值后,调用 <code>StateHasChanged</code> 进行对 <b>多选框</b> 重新渲染</p>
<div class="form-inline">
<div class="row">
<div class="form-group col-12 col-sm-6">
<Select TValue="string" Items="@Items3" OnSelectedItemChanged="@OnCascadeBindSelectClick" />
</div>
<div class="form-group col-12 col-sm-6">
<MultiSelect TValue="string" Items="@Items2" />
</div>
</div>
</div>
</Block>
<AttributeTable Items="@GetAttributes()" />
<EventTable Items="@GetEvents()" />

View File

@@ -7,9 +7,9 @@ using BootstrapBlazor.Shared.Common;
using BootstrapBlazor.Shared.Pages.Components;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading.Tasks;
using Foo = BootstrapBlazor.Shared.Pages.Components.Foo;
namespace BootstrapBlazor.Shared.Pages
{
@@ -18,67 +18,61 @@ namespace BootstrapBlazor.Shared.Pages
/// </summary>
public partial class MultiSelects
{
/// <summary>
/// 获得/设置 Logger 实例
/// </summary>
[NotNull]
private Logger? Trace { get; set; }
/// <summary>
/// 获得 默认数据集合
/// </summary>
private readonly IEnumerable<SelectedItem> Items = new SelectedItem[]
{
new SelectedItem ("Beijing", "北京"),
new SelectedItem ("Shanghai", "上海"),
new SelectedItem ("Guangzhou", "广州"),
new SelectedItem ("Shenzhen", "深圳"),
new SelectedItem ("Chengdu", "成都"),
new SelectedItem ("Wuhan", "武汉"),
new SelectedItem ("Dalian", "大连"),
new SelectedItem ("Hangzhou", "杭州"),
new SelectedItem ("Lianyungang", "连云港"),
};
[NotNull]
private Logger? Trace2 { get; set; }
/// <summary>
/// 获得 默认数据集合
/// 级联绑定菜单
/// </summary>
private readonly IEnumerable<SelectedItem> LongItems = new SelectedItem[]
/// <param name="item"></param>
private async Task OnCascadeBindSelectClick(SelectedItem item)
{
new SelectedItem ("1", "特别甜的东瓜(特别甜的东瓜)"),
new SelectedItem ("2", "特别甜的西瓜(特别甜的西瓜)"),
new SelectedItem ("3", "特别甜的南瓜(特别甜的南瓜)"),
new SelectedItem ("4", "特别甜的傻瓜(特别甜的傻瓜)"),
new SelectedItem ("5", "特别甜的金瓜(特别甜的金瓜)"),
new SelectedItem ("6", "特别甜的木瓜(特别甜的木瓜)"),
new SelectedItem ("7", "特别甜的水瓜(特别甜的水瓜)"),
new SelectedItem ("8", "特别甜的火瓜(特别甜的火瓜)"),
new SelectedItem ("9", "特别甜的土瓜(特别甜的土瓜)"),
};
private string SelectedLongItemsValue { get; set; } = "";
private string SelectedMaxItemsValue { get; set; } = "";
private string SelectedMinItemsValue { get; set; } = "";
private string SelectedItemsValue { get; set; } = "Beijing,Chengdu";
// 模拟异步获取数据源
await Task.Delay(100);
if (item.Value == "Beijing")
{
Items2 = new List<SelectedItem>(new[]
{
new SelectedItem("1","朝阳区") { Active = true },
new SelectedItem("2","海淀区")
});
}
else if (item.Value == "Shanghai")
{
Items2 = new List<SelectedItem>(new[]
{
new SelectedItem("1","静安区"),
new SelectedItem("2","黄浦区") {Active = true },
});
}
else
{
Items2 = new List<SelectedItem>();
}
StateHasChanged();
}
private void AddItems()
{
SelectedItemsValue = "Beijing,Chengdu,Hangzhou,Lianyungang";
SelectedItemsValue = "Beijing,Shanghai,Guangzhou";
}
private void RemoveItems()
{
SelectedItemsValue = "Beijing,Chengdu";
SelectedItemsValue = "Beijing";
}
private void AddListItems()
{
SelectedArrayValues = "Beijing,Chengdu,Hangzhou,Lianyungang".Split(',');
SelectedArrayValues = "Beijing,Shanghai".Split(',');
}
private void RemoveListItems()
{
SelectedArrayValues = "Beijing,Chengdu".Split(',');
SelectedArrayValues = new[] { "Beijing" };
}
private void AddArrayItems()
@@ -97,12 +91,19 @@ namespace BootstrapBlazor.Shared.Pages
private IEnumerable<SelectedItem> OnSearch(string searchText)
{
Trace.Log($"搜索文字:{searchText}");
return Items.Where(i => i.Text.Contains(searchText, System.StringComparison.OrdinalIgnoreCase));
}
private Task OnSelectedItemsChanged(IEnumerable<SelectedItem> items)
{
Trace?.Log($"选中项集合:{string.Join(",", items.Select(i => i.Value))}");
Trace.Log($"选中项集合:{string.Join(",", items.Select(i => i.Value))}");
return Task.CompletedTask;
}
private Task OnSelectedItemsChanged8(IEnumerable<SelectedItem> items)
{
Trace2.Log($"选中项集合:{string.Join(",", items.Select(i => i.Value))}");
return Task.CompletedTask;
}
@@ -115,11 +116,173 @@ namespace BootstrapBlazor.Shared.Pages
}
private string SelectedLongItemsValue1 { get; set; } = "";
private string SelectedLongItemsValue2 { get; set; } = "";
private string SelectedLongItemsValue3 { get; set; } = "";
private string SelectedMaxItemsValue { get; set; } = "";
private string SelectedMinItemsValue { get; set; } = "";
private string SelectedItemsValue { get; set; } = "Beijing";
private string SelectedItemsValue6 { get; set; } = "Beijing";
private string SelectedItemsValue7 { get; set; } = "Beijing";
private string SelectedItemsValue8 { get; set; } = "Beijing";
private IEnumerable<SelectedItem> Items { get; set; } = new[] {
new SelectedItem ("Beijing", "北京"),
new SelectedItem ("Shanghai", "上海"),
new SelectedItem ("Guangzhou", "广州"),
new SelectedItem ("Shenzhen", "深圳"),
new SelectedItem ("Chengdu", "成都"),
new SelectedItem ("Wuhan", "武汉"),
new SelectedItem ("Dalian", "大连"),
new SelectedItem ("Hangzhou", "杭州"),
new SelectedItem ("Lianyungang", "连云港")
};
private List<SelectedItem> Items2 { get; set; } = new List<SelectedItem>();
private readonly List<SelectedItem> Items3 = new SelectedItem[]
{
new SelectedItem ("", "请选择 ..."),
new SelectedItem ("Beijing", "北京") { Active = true },
new SelectedItem ("Shanghai", "上海"),
new SelectedItem ("Hangzhou", "杭州")
}.ToList();
private IEnumerable<SelectedItem> Items4 { get; set; } = new[] {
new SelectedItem ("Beijing", "北京"),
new SelectedItem ("Shanghai", "上海"),
new SelectedItem ("Guangzhou", "广州")
};
private IEnumerable<SelectedItem> Items5 { get; set; } = new[] {
new SelectedItem ("Beijing", "北京"),
new SelectedItem ("Shanghai", "上海"),
new SelectedItem ("Guangzhou", "广州")
};
private IEnumerable<SelectedItem> Items6 { get; set; } = new[] {
new SelectedItem ("Beijing", "北京"),
new SelectedItem ("Shanghai", "上海"),
new SelectedItem ("Guangzhou", "广州")
};
private IEnumerable<SelectedItem> Items7 { get; set; } = new[] {
new SelectedItem ("Beijing", "北京"),
new SelectedItem ("Shanghai", "上海"),
new SelectedItem ("Guangzhou", "广州")
};
private IEnumerable<SelectedItem> Items8 { get; set; } = new[] {
new SelectedItem ("Beijing", "北京"),
new SelectedItem ("Shanghai", "上海"),
new SelectedItem ("Guangzhou", "广州")
};
private IEnumerable<SelectedItem> Items9 { get; set; } = new[] {
new SelectedItem ("Beijing", "北京"),
new SelectedItem ("Shanghai", "上海"),
new SelectedItem ("Guangzhou", "广州")
};
private IEnumerable<SelectedItem> Items10 { get; set; } = new[] {
new SelectedItem ("Beijing", "北京"),
new SelectedItem ("Shanghai", "上海"),
new SelectedItem ("Guangzhou", "广州")
};
private IEnumerable<SelectedItem> Items11 { get; set; } = new[] {
new SelectedItem ("Beijing", "北京"),
new SelectedItem ("Shanghai", "上海"),
new SelectedItem ("Guangzhou", "广州")
};
private IEnumerable<SelectedItem> LongItems { get; set; } = new[]
{
new SelectedItem ("1", "特别甜的东瓜(特别甜的东瓜)"),
new SelectedItem ("2", "特别甜的西瓜(特别甜的西瓜)"),
new SelectedItem ("3", "特别甜的南瓜(特别甜的南瓜)"),
new SelectedItem ("4", "特别甜的傻瓜(特别甜的傻瓜)"),
new SelectedItem ("5", "特别甜的金瓜(特别甜的金瓜)"),
new SelectedItem ("6", "特别甜的木瓜(特别甜的木瓜)"),
new SelectedItem ("7", "特别甜的水瓜(特别甜的水瓜)"),
new SelectedItem ("8", "特别甜的火瓜(特别甜的火瓜)"),
new SelectedItem ("9", "特别甜的土瓜(特别甜的土瓜)"),
};
private IEnumerable<SelectedItem> LongItems1 { get; set; } = new[]
{
new SelectedItem ("1", "特别甜的东瓜(特别甜的东瓜)"),
new SelectedItem ("2", "特别甜的西瓜(特别甜的西瓜)"),
new SelectedItem ("3", "特别甜的南瓜(特别甜的南瓜)"),
new SelectedItem ("4", "特别甜的傻瓜(特别甜的傻瓜)"),
new SelectedItem ("5", "特别甜的金瓜(特别甜的金瓜)"),
new SelectedItem ("6", "特别甜的木瓜(特别甜的木瓜)"),
new SelectedItem ("7", "特别甜的水瓜(特别甜的水瓜)"),
new SelectedItem ("8", "特别甜的火瓜(特别甜的火瓜)"),
new SelectedItem ("9", "特别甜的土瓜(特别甜的土瓜)"),
};
private IEnumerable<SelectedItem> LongItems2 { get; set; } = new[]
{
new SelectedItem ("1", "特别甜的东瓜(特别甜的东瓜)"),
new SelectedItem ("2", "特别甜的西瓜(特别甜的西瓜)"),
new SelectedItem ("3", "特别甜的南瓜(特别甜的南瓜)"),
new SelectedItem ("4", "特别甜的傻瓜(特别甜的傻瓜)"),
new SelectedItem ("5", "特别甜的金瓜(特别甜的金瓜)"),
new SelectedItem ("6", "特别甜的木瓜(特别甜的木瓜)"),
new SelectedItem ("7", "特别甜的水瓜(特别甜的水瓜)"),
new SelectedItem ("8", "特别甜的火瓜(特别甜的火瓜)"),
new SelectedItem ("9", "特别甜的土瓜(特别甜的土瓜)"),
};
private IEnumerable<SelectedItem> LongItems3 { get; set; } = new[]
{
new SelectedItem ("1", "特别甜的东瓜(特别甜的东瓜)"),
new SelectedItem ("2", "特别甜的西瓜(特别甜的西瓜)"),
new SelectedItem ("3", "特别甜的南瓜(特别甜的南瓜)"),
new SelectedItem ("4", "特别甜的傻瓜(特别甜的傻瓜)"),
new SelectedItem ("5", "特别甜的金瓜(特别甜的金瓜)"),
new SelectedItem ("6", "特别甜的木瓜(特别甜的木瓜)"),
new SelectedItem ("7", "特别甜的水瓜(特别甜的水瓜)"),
new SelectedItem ("8", "特别甜的火瓜(特别甜的火瓜)"),
new SelectedItem ("9", "特别甜的土瓜(特别甜的土瓜)"),
};
private IEnumerable<SelectedItem> LongItems4 { get; set; } = new[]
{
new SelectedItem ("1", "特别甜的东瓜(特别甜的东瓜)"),
new SelectedItem ("2", "特别甜的西瓜(特别甜的西瓜)"),
new SelectedItem ("3", "特别甜的南瓜(特别甜的南瓜)"),
new SelectedItem ("4", "特别甜的傻瓜(特别甜的傻瓜)"),
new SelectedItem ("5", "特别甜的金瓜(特别甜的金瓜)"),
new SelectedItem ("6", "特别甜的木瓜(特别甜的木瓜)"),
new SelectedItem ("7", "特别甜的水瓜(特别甜的水瓜)"),
new SelectedItem ("8", "特别甜的火瓜(特别甜的火瓜)"),
new SelectedItem ("9", "特别甜的土瓜(特别甜的土瓜)"),
};
private IEnumerable<SelectedItem> LongItems5 { get; set; } = new[]
{
new SelectedItem ("1", "特别甜的东瓜(特别甜的东瓜)"),
new SelectedItem ("2", "特别甜的西瓜(特别甜的西瓜)"),
new SelectedItem ("3", "特别甜的南瓜(特别甜的南瓜)"),
new SelectedItem ("4", "特别甜的傻瓜(特别甜的傻瓜)"),
new SelectedItem ("5", "特别甜的金瓜(特别甜的金瓜)"),
new SelectedItem ("6", "特别甜的木瓜(特别甜的木瓜)"),
new SelectedItem ("7", "特别甜的水瓜(特别甜的水瓜)"),
new SelectedItem ("8", "特别甜的火瓜(特别甜的火瓜)"),
new SelectedItem ("9", "特别甜的土瓜(特别甜的土瓜)"),
};
/// <summary>
/// 获得事件方法
/// </summary>
/// <returns></returns>
private static IEnumerable<EventItem> GetEvents() => new EventItem[]
private static IEnumerable<EventItem> GetEvents() => new[]
{
new EventItem()
{
@@ -139,7 +302,7 @@ namespace BootstrapBlazor.Shared.Pages
/// 获得属性方法
/// </summary>
/// <returns></returns>
private static IEnumerable<AttributeItem> GetAttributes() => new AttributeItem[]
private static IEnumerable<AttributeItem> GetAttributes() => new[]
{
// TODO: 移动到数据库中
new AttributeItem() {

View File

@@ -20,7 +20,7 @@ namespace BootstrapBlazor.Shared.Pages
{
var ret = new List<NavLink>();
var link = new NavLink();
link.SetParametersAsync(ParameterView.FromDictionary(new Dictionary<string, object>()
link.SetParametersAsync(ParameterView.FromDictionary(new Dictionary<string, object?>()
{
["href"] = WebsiteOption.Value.AdminUrl,
["class"] = "nav-link nav-item",
@@ -38,7 +38,7 @@ namespace BootstrapBlazor.Shared.Pages
/// 获得属性方法
/// </summary>
/// <returns></returns>
private IEnumerable<AttributeItem> GetAttributes() => new AttributeItem[]
private static IEnumerable<AttributeItem> GetAttributes() => new AttributeItem[]
{
// TODO: 移动到数据库中
new AttributeItem() {

View File

@@ -11,7 +11,7 @@
<PopConfirmButton Placement="Placement.Bottom" ConfirmButtonColor="Color.Danger" Text="下面弹框" Content="这是一段内容确定删除吗?" OnConfirm="@OnConfirm" OnClose="@OnClose" />
</div>
<div class="d-flex justify-content-between m-4 align-items-center flex-fill">
<PopConfirmButton Placement="Placement.Right" CloseButtonText="取消" Text="右侧弹窗" Content="这是一段内容确定删除吗?" OnConfirm="@OnConfirm" OnClose="@OnClose" />
<PopConfirmButton Placement="Placement.Right" Text="右侧弹窗" Content="这是一段内容确定删除吗?" OnConfirm="@OnConfirm" OnClose="@OnClose" />
<PopConfirmButton Placement="Placement.Left" Text="左侧弹窗" Content="这是一段内容确定删除吗?" OnConfirm="@OnConfirm" OnClose="@OnClose" />
</div>
<div class="d-flex justify-content-center">

View File

@@ -103,7 +103,7 @@ namespace BootstrapBlazor.Shared.Pages
DefaultValue = "fa fa-exclamation-circle text-info"
},
new AttributeItem() {
Name = "Cotent",
Name = "Content",
Description = "显示文字",
Type = "string",
ValueList = "",

View File

@@ -5,7 +5,33 @@
<h4>可简单设置一行显示的组件数量</h4>
<Block Title="放置普通控件" Introduction="将自己的组件放到 <code>Row</code> 内部即可">
<Row ItemsPerRow="ItemsPerRowEnum.Three">
<p><b>行显示 3 个,采用 <code>Row</code></b></p>
<Row ItemsPerRow="ItemsPerRow.Three">
<Card>
<CardBody>
<h5 class="card-title">Card 1</h5>
<p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
<a href="#" class="btn btn-primary">Go somewhere</a>
</CardBody>
</Card>
<Card>
<CardBody>
<h5 class="card-title">Card 2</h5>
<p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
<a href="#" class="btn btn-primary">Go somewhere</a>
</CardBody>
</Card>
<Card>
<CardBody>
<h5 class="card-title">Card 3</h5>
<p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
<a href="#" class="btn btn-primary">Go somewhere</a>
</CardBody>
</Card>
</Row>
<p class="mt-3"><b>行显示 3 个,采用 <code>FormRow</code></b></p>
<Row RowType="RowType.FormRow" ItemsPerRow="ItemsPerRow.Three">
<Card>
<CardBody>
<h5 class="card-title">Card 1</h5>
@@ -29,79 +55,148 @@
</Card>
</Row>
</Block>
<Block Title="放置表单控件(内联)" Introduction="当放置表单控件时可以指定RowType为FormInline会将Label显示在左边控件显示原始大小">
<Block Title="放置表单控件(内联)" Introduction="当放置表单控件时,可以指定 <code>RowType</code> 为 <code>Inline</code>,会将 <b>Label</b> 显示在左边,控件显示原始大小">
<p>本例中 <code>Row</code> 组件内置于 <code>ValidateForm</code> 组件内,自动增加前置 <code>Label</code> 标签</p>
<ValidateForm Model="@Model">
<Row ItemsPerRow="ItemsPerRowEnum.Three" RowType="RowTypeEnum.FormInline" >
<CheckboxList @bind-Value="@Educations" />
<Row ItemsPerRow="ItemsPerRow.Three" RowType="RowType.Inline">
<CheckboxList @bind-Value="@Model.Hobby" Items="Hobbys" />
<BootstrapInput @bind-Value="@Model.Address" />
<BootstrapInput @bind-Value="@Model.DateTime" />
<BootstrapInput @bind-Value="@Model.Id" />
<BootstrapInput @bind-Value="@Model.Complete" />
<DateTimePicker @bind-Value="@Model.DateTime" />
<BootstrapInputNumber @bind-Value="@Model.Count" />
<Switch @bind-Value="@Model.Complete" />
<Select @bind-Value="@Model.Education" />
</Row>
</ValidateForm>
</Block>
<Block Title="放置表单控件(充满)" Introduction="当放置表单控件时可以指定RowType为FormRow会将Label显示在上边控件充满">
<Block Title="放置表单控件(充满)" Introduction="当放置表单控件时,可以指定 <code>RowType</code> 为 <code>FormRow</code>,会将 <b>Label</b> 显示在上边,控件充满">
<p>本例中 <code>Row</code> 组件内置于 <code>ValidateForm</code> 组件内,自动增加前置 <code>Label</code> 标签</p>
<ValidateForm Model="@Model">
<Row ItemsPerRow="ItemsPerRowEnum.Three" RowType="RowTypeEnum.FormRow" MaxCount="5">
<CheckboxList @bind-Value="@Educations" />
<Row ItemsPerRow="ItemsPerRow.Three" RowType="RowType.FormRow">
<CheckboxList @bind-Value="@Model.Hobby" Items="Hobbys" />
<BootstrapInput @bind-Value="@Model.Address" />
<BootstrapInput @bind-Value="@Model.DateTime" />
<BootstrapInput @bind-Value="@Model.Id" />
<BootstrapInput @bind-Value="@Model.Complete" />
<DateTimePicker @bind-Value="@Model.DateTime" />
<BootstrapInputNumber @bind-Value="@Model.Count" />
<Switch @bind-Value="@Model.Complete" />
<Select @bind-Value="@Model.Education" />
</Row>
</ValidateForm>
</Block>
<Block Title="Row嵌套" Introduction="Row中还可以嵌套Row比如下面最外层的Row设置一行显示两个控件第一个是TextBox第二个还是个Row第二个Row继续设置显示两个控件">
<Block Title="嵌套使用" Introduction="<code>Row</code> 组件支持嵌套使用,比如下面最外层的 <code>Row</code> 设置一行显示两个控件,第一个是 <code>TextBox</code>,第二个还是 <code>Row</code>,第二个 <code>Row</code> 继续设置显示两个控件">
<p>本例中 <code>Row</code> 组件内置于 <code>ValidateForm</code> 组件内,自动增加前置 <code>Label</code> 标签</p>
<Pre>&lt;Row ItemsPerRow="ItemsPerRow.Two" RowType="RowType.FormRow"&gt;
&lt;BootstrapInput @@bind-Value="@@Model.Name" /&gt;
&lt;Row ItemsPerRow="ItemsPerRow.Two"&gt;
&lt;Switch @@bind-Value="@@Model.Complete" /&gt;
&lt;BootstrapInput @@bind-Value="@@Model.Address" /&gt;
&lt;/Row&gt;
&lt;/Row&gt;
</Pre>
<ValidateForm Model="@Model">
<Row ItemsPerRow="ItemsPerRowEnum.Two" RowType="RowTypeEnum.FormRow">
<BootstrapInput @bind-Value="@Model.Address" />
<Row ItemsPerRow="ItemsPerRowEnum.Two">
<BootstrapInput @bind-Value="@Model.Address" />
<Row ItemsPerRow="ItemsPerRow.Two" RowType="RowType.FormRow">
<BootstrapInput @bind-Value="@Model.Name" />
<Row ItemsPerRow="ItemsPerRow.Two">
<Switch @bind-Value="@Model.Complete" />
<BootstrapInput @bind-Value="@Model.Address" />
</Row>
</Row>
</ValidateForm>
</Block>
<Block Title="子Row跨列" Introduction="子Row中通过指定ColSpan可以设置跨父Row的列数组合这些功能可以实现复杂布局">
<Block Title="跨列功能" Introduction="<code>Row</code> 组件可以通过指定 <code>ColSpan</code> 值设置跨列数,组合这些功能可以实现复杂布局">
<p>本例中 <code>Row</code> 组件内置于 <code>ValidateForm</code> 组件内,自动增加前置 <code>Label</code> 标签</p>
<p><b>行显示 4 个</b></p>
<Pre>&lt;Row ItemsPerRow="ItemsPerRow.Four" RowType="RowType.FormRow"&gt;
&lt;BootstrapInput @@bind-Value="@@Model.Name" /&gt;
&lt;BootstrapInput @@bind-Value="@@Model.Address" /&gt;
&lt;BootstrapInputNumber @@bind-Value="@@Model.Count" /&gt;
&lt;Select @@bind-Value="@@Model.Education" /&gt;
&lt;/Row&gt;
</Pre>
<ValidateForm Model="@Model">
<Row ItemsPerRow="ItemsPerRowEnum.Four" RowType="RowTypeEnum.FormRow">
<BootstrapInput @bind-Value="@Model.Address" />
<BootstrapInput @bind-Value="@Model.Address" />
<Row ItemsPerRow="ItemsPerRow.Four" RowType="RowType.FormRow">
<BootstrapInput @bind-Value="@Model.Name" />
<BootstrapInput @bind-Value="@Model.Address" />
<BootstrapInputNumber @bind-Value="@Model.Count" />
<Select @bind-Value="@Model.Education" />
</Row>
</ValidateForm>
<p><b>行显示 2 个</b></p>
<Pre>&lt;Row ItemsPerRow="ItemsPerRow.Two" RowType="RowType.FormRow"&gt;
&lt;BootstrapInput @@bind-Value="@@Model.Name" /&gt;
&lt;BootstrapInput @@bind-Value="@@Model.Address" /&gt;
&lt;/Row&gt;
</Pre>
<ValidateForm Model="@Model">
<Row ItemsPerRow="ItemsPerRow.Two" RowType="RowType.FormRow">
<BootstrapInput @bind-Value="@Model.Name" />
<BootstrapInput @bind-Value="@Model.Address" />
</Row>
<Row ItemsPerRow="ItemsPerRowEnum.Two" RowType="RowTypeEnum.FormRow">
<BootstrapInput @bind-Value="@Model.Address" />
<BootstrapInput @bind-Value="@Model.Address" />
</Row>
<Row ItemsPerRow="ItemsPerRowEnum.Four" RowType="RowTypeEnum.FormRow">
<BootstrapInput @bind-Value="@Model.Address" />
</ValidateForm>
<p><b>行显示 4 个 <code>Address</code> 占 2 列</b></p>
<Pre>&lt;Row ItemsPerRow="ItemsPerRow.Four" RowType="RowType.FormRow"&gt;
&lt;BootstrapInput @@bind-Value="@@Model.Name" /&gt;
&lt;Row ColSpan="2"&gt;
&lt;BootstrapInput @@bind-Value="@@Model.Address" /&gt;
&lt;/Row&gt;
&lt;Select @@bind-Value="@Model.Education" /&gt;
&lt;/Row&gt;
</Pre>
<ValidateForm Model="@Model">
<Row ItemsPerRow="ItemsPerRow.Four" RowType="RowType.FormRow">
<BootstrapInput @bind-Value="@Model.Name" />
<Row ColSpan="2">
<BootstrapInput @bind-Value="@Model.Address" />
</Row>
<BootstrapInput @bind-Value="@Model.Address" />
<Select @bind-Value="@Model.Education" />
</Row>
<Row ItemsPerRow="ItemsPerRowEnum.Four" RowType="RowTypeEnum.FormRow">
<BootstrapInput @bind-Value="@Model.Address" />
</ValidateForm>
<p><b>行显示 4 个,第二个组件 <code>ColSpan</code> 设置为 3</b></p>
<Pre>&lt;Row ItemsPerRow="ItemsPerRow.Four" RowType="RowType.FormRow"&gt;
&lt;BootstrapInput @@bind-Value="@@Model.Name" /&gt;
&lt;Row ColSpan="3"&gt;
&lt;BootstrapInput @@bind-Value="@@Model.Address" /&gt;
&lt;/Row&gt;
&lt;/Row&gt;
</Pre>
<ValidateForm Model="@Model">
<Row ItemsPerRow="ItemsPerRow.Four" RowType="RowType.FormRow">
<BootstrapInput @bind-Value="@Model.Name" />
<Row ColSpan="3">
<BootstrapInput @bind-Value="@Model.Address" />
</Row>
</Row>
<Row ItemsPerRow="ItemsPerRowEnum.Four" RowType="RowTypeEnum.FormRow">
</ValidateForm>
<p><b>行显示 2 个,第一个组件 <code>ColSpan</code> 设置为 3</b></p>
<Pre>&lt;Row ItemsPerRow="ItemsPerRow.Four" RowType="RowType.FormRow"&gt;
&lt;Row ColSpan="3"&gt;
&lt;CheckboxList @@bind-Value="@@Model.Hobby" Items="@@Hobbys" /&gt;
&lt;/Row&gt;
&lt;BootstrapInput @@bind-Value="@@Model.Address" /&gt;
&lt;/Row&gt;
</Pre>
<ValidateForm Model="@Model">
<Row ItemsPerRow="ItemsPerRow.Four" RowType="RowType.FormRow">
<Row ColSpan="3">
<BootstrapInput @bind-Value="@Model.Address" />
<CheckboxList @bind-Value="@Model.Hobby" Items="@Hobbys" />
</Row>
<BootstrapInput @bind-Value="@Model.Address" />
</Row>
<Row ItemsPerRow="ItemsPerRowEnum.One">
</ValidateForm>
<p>行显示一个组件</p>
<ValidateForm Model="@Model">
<Row ItemsPerRow="ItemsPerRow.One">
<BootstrapInput @bind-Value="@Model.Address" />
</Row>
</ValidateForm>
</Block>
<Tips>
注意由于Blazor还无法区分子组件的级层如果Row中包含的组件还输出了其他子组件Row也会加载子组件导致排版错误可以通过指定MaxCount来指定Row中显示组件的个数
</Tips>
<AttributeTable Items="@GetAttributes()" />

View File

@@ -2,10 +2,15 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Website: https://www.blazor.zone or https://argozhang.github.io/
using BootstrapBlazor.Components;
using BootstrapBlazor.Shared.Common;
using BootstrapBlazor.Shared.Pages.Components;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Localization;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics.CodeAnalysis;
namespace BootstrapBlazor.Shared.Pages
{
@@ -14,17 +19,33 @@ namespace BootstrapBlazor.Shared.Pages
/// </summary>
public sealed partial class Rows
{
private Foo Model { get; } = new Foo()
[Inject]
[NotNull]
private IStringLocalizer<Foo>? Localizer { get; set; }
private RowFoo Model { get; } = new()
{
Name = "张三",
Count = 23,
Address = "测试地址",
DateTime = new DateTime(1997, 12, 05),
Education = EnumEducation.Middel
Educations = new List<EnumEducation> { EnumEducation.Primary, EnumEducation.Middel }
};
private List<EnumEducation> Educations = new List<EnumEducation> { EnumEducation.Middel, EnumEducation.Primary };
private IEnumerable<AttributeItem> GetAttributes() => new AttributeItem[]
[NotNull]
private IEnumerable<SelectedItem>? Hobbys { get; set; }
/// <summary>
/// OnInitialized 方法
/// </summary>
protected override void OnInitialized()
{
base.OnInitialized();
Hobbys = Foo.GenerateHobbys(Localizer);
}
private static IEnumerable<AttributeItem> GetAttributes() => new AttributeItem[]
{
new AttributeItem() {
Name = "ItemsPerRow",
@@ -54,8 +75,17 @@ namespace BootstrapBlazor.Shared.Pages
ValueList = "-",
DefaultValue = "null"
}
};
private class RowFoo : Foo
{
/// <summary>
///
/// </summary>
[Required(ErrorMessage = "请选择学历")]
[Display(Name = "学历")]
[AutoGenerateColumn(Order = 60)]
public List<EnumEducation>? Educations { get; set; }
}
}
}

View File

@@ -6,31 +6,32 @@
<h4>当选项过多时,使用下拉菜单展示并选择内容</h4>
<Block Title="Select 下拉选择框" Introduction="提供各种颜色的下拉选择框">
<p>本例中,第一个下拉框没有进行 <code>Value</code> 双向绑定,所以选择不同选项时仅自己变化,其余下拉框共用同一数据源 <code>Items</code> 并且双向绑定 <code>Value</code> 值,选择不同选项时一同变化</p>
<div class="form-inline">
<div class="row">
<div class="form-group col-12 col-sm-6">
<Select TValue="string" Items="@Items" OnSelectedItemChanged="@OnItemChanged"></Select>
</div>
<div class="form-group col-12 col-sm-6">
<Select TValue="string" Color="Color.Primary" Items="@Items" OnSelectedItemChanged="@OnItemChanged"></Select>
<Select Color="Color.Primary" Items="@Items" OnSelectedItemChanged="@OnItemChanged" @bind-Value="@Model.Name"></Select>
</div>
<div class="form-group col-12 col-sm-6">
<Select TValue="string" Color="Color.Success" Items="@Items" OnSelectedItemChanged="@OnItemChanged"></Select>
<Select Color="Color.Success" @bind-Items="@Items" OnSelectedItemChanged="@OnItemChanged" @bind-Value="@Model.Name"></Select>
</div>
<div class="form-group col-12 col-sm-6">
<Select TValue="string" Color="Color.Danger" Items="@Items" OnSelectedItemChanged="@OnItemChanged"></Select>
<Select Color="Color.Danger" @bind-Items="@Items" OnSelectedItemChanged="@OnItemChanged" @bind-Value="@Model.Name"></Select>
</div>
<div class="form-group col-12 col-sm-6">
<Select TValue="string" Color="Color.Warning" Items="@Items" OnSelectedItemChanged="@OnItemChanged"></Select>
<Select Color="Color.Warning" @bind-Items="@Items" OnSelectedItemChanged="@OnItemChanged" @bind-Value="@Model.Name"></Select>
</div>
<div class="form-group col-12 col-sm-6">
<Select TValue="string" Color="Color.Info" Items="@Items" OnSelectedItemChanged="@OnItemChanged"></Select>
<Select Color="Color.Info" @bind-Items="@Items" OnSelectedItemChanged="@OnItemChanged" @bind-Value="@Model.Name"></Select>
</div>
<div class="form-group col-12 col-sm-6">
<Select TValue="string" Color="Color.Secondary" Items="@Items" OnSelectedItemChanged="@OnItemChanged"></Select>
<Select Color="Color.Secondary" @bind-Items="@Items" OnSelectedItemChanged="@OnItemChanged" @bind-Value="@Model.Name"></Select>
</div>
<div class="form-group col-12 col-sm-6">
<Select TValue="string" Color="Color.Dark" Items="@Items" OnSelectedItemChanged="@OnItemChanged"></Select>
<Select Color="Color.Dark" @bind-Items="@Items" OnSelectedItemChanged="@OnItemChanged" @bind-Value="@Model.Name"></Select>
</div>
</div>
</div>
@@ -63,6 +64,14 @@
</div>
</div>
</div>
<p>下拉框内选项 <b>禁用</b> 示例</p>
<div class="form-inline">
<div class="row">
<div class="form-group col-12 col-sm-6">
<Select TValue="string" Items="@Items4" />
</div>
</div>
</div>
</Block>
<Block Title="Select 双向绑定" Introduction="通过 <code>Select</code> 组件绑定 <code>Model.Name</code> 属性,改变下拉框选项时,文本框内的数值随之改变。">
@@ -85,7 +94,7 @@
<Select TValue="string" Items="@Items3" OnSelectedItemChanged="@OnCascadeBindSelectClick" />
</div>
<div class="form-group col-12 col-sm-6">
<Select @ref="Select2" TValue="string" Items="@Items2" />
<Select TValue="string" Items="@Items2" />
</div>
<div class="form-group col-12">
<Button Text="弹窗中级联示例" OnClickWithoutRender="@OnShowDialog" />
@@ -179,11 +188,20 @@
</Block>
<Block Title="枚举数据" Introduction="<code>Select</code> 组件绑定枚举类型示例">
<p>本次展现的是通过 <code>Select</code> 组件绑定枚举类型 <code>EnumEducation</code>,通过选项的更改绑定数据</p>
<p>当绑定值为可为空枚举类型时,组件内部自动通过 <code>PlaceHolder</code> 值添加首选项,未设置 <code>PlaceHolder</code> 值时,使用资源文件中的 <b>请选择 ...</b> 作为首选项,本示例绑定 <code>EnumEducation</code> 枚举类型</p>
<p>绑定值为枚举类型时,设置 <code>PalceHolder</code> 无效</p>
<div class="form-inline">
<div class="row">
<div class="form-group col-12 col-sm-6">
<Select @bind-Value="@SelectedEnumItem">
<Select @bind-Value="@SelectedEnumItem1" PlaceHolder="@Localizer["PlaceHolder"]" ShowLabel="true" DisplayText="可为空">
</Select>
</div>
<div class="form-group col-12 col-sm-6">
<Select @bind-Value="@SelectedEnumItem1" ShowLabel="true" DisplayText="可为空">
</Select>
</div>
<div class="form-group col-12 col-sm-6">
<Select @bind-Value="@SelectedEnumItem" ShowLabel="true" DisplayText="不为空">
</Select>
</div>
<div class="form-group col-12 col-sm-6">

View File

@@ -5,8 +5,12 @@
using BootstrapBlazor.Components;
using BootstrapBlazor.Shared.Common;
using BootstrapBlazor.Shared.Pages.Components;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Localization;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading.Tasks;
namespace BootstrapBlazor.Shared.Pages
@@ -31,10 +35,14 @@ namespace BootstrapBlazor.Shared.Pages
/// </summary>
private Logger? Trace { get; set; }
[Inject]
[NotNull]
private IStringLocalizer<Selects>? Localizer { get; set; }
/// <summary>
/// 获得 默认数据集合
/// </summary>
private readonly IEnumerable<SelectedItem> Items = new SelectedItem[]
private IEnumerable<SelectedItem> Items { get; set; } = new[]
{
new SelectedItem ("Beijing", "北京"),
new SelectedItem ("Shanghai", "上海") { Active = true },
@@ -43,7 +51,17 @@ namespace BootstrapBlazor.Shared.Pages
/// <summary>
/// 获得 默认数据集合
/// </summary>
private readonly IEnumerable<SelectedItem> StringItems = new SelectedItem[]
private readonly IEnumerable<SelectedItem> Items4 = new[]
{
new SelectedItem ("Beijing", "北京") { IsDisabled = true},
new SelectedItem ("Shanghai", "上海") { Active = true },
new SelectedItem ("Guangzhou", "广州")
};
/// <summary>
/// 获得 默认数据集合
/// </summary>
private readonly IEnumerable<SelectedItem> StringItems = new[]
{
new SelectedItem ("1", "1"),
new SelectedItem ("12", "12"),
@@ -92,47 +110,48 @@ namespace BootstrapBlazor.Shared.Pages
private Task OnItemChanged(SelectedItem item)
{
Trace?.Log($"SelectedItem Text: {item.Text} Value: {item.Value} Selected");
StateHasChanged();
return Task.CompletedTask;
}
private Select<string>? Select2 { get; set; }
/// <summary>
/// 级联绑定菜单
/// </summary>
/// <param name="item"></param>
private Task OnCascadeBindSelectClick(SelectedItem item)
private async Task OnCascadeBindSelectClick(SelectedItem item)
{
_item2.Clear();
// 模拟异步通讯切换线程
await Task.Delay(10);
if (item.Value == "Beijing")
{
_item2.AddRange(new SelectedItem[]
Items2 = new SelectedItem[]
{
new SelectedItem("1","朝阳区"),
new SelectedItem("1","朝阳区") { Active = true},
new SelectedItem("2","海淀区"),
});
};
}
else if (item.Value == "Shanghai")
{
_item2.AddRange(new SelectedItem[]
Items2 = new SelectedItem[]
{
new SelectedItem("1","静安区"),
new SelectedItem("2","黄浦区"),
});
new SelectedItem("2","黄浦区") { Active = true } ,
};
}
Select2?.SetItems(_item2);
return Task.CompletedTask;
else
{
Items2 = Enumerable.Empty<SelectedItem>();
}
StateHasChanged();
}
private Task OnShowDialog() => Dialog.Show(new DialogOption()
{
Title = "弹窗中使用级联下拉框",
Component = DynamicComponent.CreateComponent<CustomerSelectDialog>()
Component = BootstrapDynamicComponent.CreateComponent<CustomerSelectDialog>()
});
private readonly List<SelectedItem> _item2 = new();
private IEnumerable<SelectedItem> Items2 => _item2;
private IEnumerable<SelectedItem>? Items2 { get; set; }
private IEnumerable<SelectedItem> NullableIntItems { get; set; } = new SelectedItem[]
{
@@ -164,6 +183,8 @@ namespace BootstrapBlazor.Shared.Pages
private EnumEducation SelectedEnumItem { get; set; } = EnumEducation.Primary;
private EnumEducation? SelectedEnumItem1 { get; set; }
/// <summary>
/// 获得事件方法
/// </summary>

View File

@@ -1,5 +1,4 @@
@page "/swals"
@inject SwalService SwalService
<h3>SweetAlert 弹窗组件</h3>

View File

@@ -8,6 +8,7 @@ using BootstrapBlazor.Shared.Pages.Components;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
namespace BootstrapBlazor.Shared.Pages
@@ -35,6 +36,10 @@ namespace BootstrapBlazor.Shared.Pages
Content = "我是 Content"
});
[Inject]
[NotNull]
private SwalService? SwalService { get; set; }
private async Task ShowButtons()
{
var op = new SwalOption()
@@ -78,7 +83,7 @@ namespace BootstrapBlazor.Shared.Pages
Title = "Oops...",
Content = "Something went wrong!",
ShowFooter = true,
FooterTemplate = DynamicComponent.CreateComponent<SwalFooter>().Render()
FooterTemplate = BootstrapDynamicComponent.CreateComponent<SwalFooter>().Render()
};
await SwalService.Show(op);
}
@@ -93,7 +98,7 @@ namespace BootstrapBlazor.Shared.Pages
ShowFooter = true,
IsAutoHide = true,
Delay = 4000,
FooterTemplate = DynamicComponent.CreateComponent<SwalFooter>().Render()
FooterTemplate = BootstrapDynamicComponent.CreateComponent<SwalFooter>().Render()
};
await SwalService.Show(op);
}
@@ -117,7 +122,7 @@ namespace BootstrapBlazor.Shared.Pages
///
/// </summary>
/// <returns></returns>
private IEnumerable<AttributeItem> GetAttributes()
private static IEnumerable<AttributeItem> GetAttributes()
{
return new AttributeItem[]
{

View File

@@ -327,6 +327,13 @@ namespace BootstrapBlazor.Shared.Pages.Table
ValueList = "true / false",
DefaultValue = "false"
},
new AttributeItem() {
Name = "IsTree",
Description = "是否为树形数据",
Type = "boolean",
ValueList = "true / false",
DefaultValue = "false"
},
new AttributeItem() {
Name = "ClickToSelect",
Description = "点击行即选中本行",
@@ -355,6 +362,20 @@ namespace BootstrapBlazor.Shared.Pages.Table
ValueList = "true / false",
DefaultValue = "false"
},
new AttributeItem() {
Name = "ShowResetSearch",
Description = "显示清空搜索按钮",
Type = "boolean",
ValueList = "true / false",
DefaultValue = "true"
},
new AttributeItem() {
Name = "ShowAdvancedSearch",
Description = "显示高级搜索按钮",
Type = "boolean",
ValueList = "true / false",
DefaultValue = "true"
},
new AttributeItem() {
Name = "ShowToolbar",
Description = "显示 Toolbar",
@@ -453,6 +474,13 @@ namespace BootstrapBlazor.Shared.Pages.Table
ValueList = " — ",
DefaultValue = " — "
},
new AttributeItem() {
Name = "OnEditAsync",
Description = "编辑按钮异步回调方法",
Type = "Func<TItem, Task>",
ValueList = " — ",
DefaultValue = " — "
},
new AttributeItem() {
Name = "OnSaveAsync",
Description = "保存按钮异步回调方法",

View File

@@ -1,5 +1,4 @@
@inherits TablesBase
@page "/tables/autorefresh"
@page "/tables/autorefresh"
<h3>自动刷新表格功能</h3>
@@ -18,11 +17,7 @@
<TableColumn @bind-Field="@context.Name" Width="100" />
<TableColumn @bind-Field="@context.Address" />
<TableColumn @bind-Field="@context.Count" />
<TableColumn @bind-Field="@context.Complete">
<Template Context="v">
<Switch IsDisabled="true" Value="v.Value" ShowInnerText="true" OnInnerText="是" OffInnerText="否" />
</Template>
</TableColumn>
<TableColumn @bind-Field="@context.Complete" ComponentType="typeof(Switch)" />
</TableColumns>
</Table>
</Block>

View File

@@ -4,8 +4,11 @@
using BootstrapBlazor.Components;
using BootstrapBlazor.Shared.Pages.Components;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Localization;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading.Tasks;
@@ -16,6 +19,15 @@ namespace BootstrapBlazor.Shared.Pages.Table
/// </summary>
public partial class TablesAutoRefresh
{
private static readonly Random random = new();
[NotNull]
private List<Foo>? Items { get; set; }
[Inject]
[NotNull]
private IStringLocalizer<Foo>? Localizer { get; set; }
private List<Foo> AutoItems { get; set; } = new List<Foo>();
/// <summary>
@@ -25,24 +37,19 @@ namespace BootstrapBlazor.Shared.Pages.Table
{
base.OnInitialized();
AutoItems = Items.Take(2).ToList();
AutoItems = Foo.GenerateFoo(Localizer).Take(2).ToList();
}
private Task<QueryData<Foo>> OnRefreshQueryAsync(QueryPageOptions options)
{
// 设置记录总数
var total = AutoItems.Count();
var total = AutoItems.Count;
var foo = Foo.Generate(Localizer);
foo.Id = total++;
foo.Name = Localizer["Foo.Name", total.ToString("D4")];
foo.Address = Localizer["Foo.Address", $"{random.Next(1000, 2000)}"];
AutoItems.Insert(0, new Foo()
{
Id = total++,
Name = $"张三 {total:d4}",
DateTime = DateTime.Now.AddDays(total - 1),
Address = $"上海市普陀区金沙江路 {random.Next(1000, 2000)} 弄",
Count = random.Next(1, 100),
Complete = random.Next(1, 100) > 50,
Education = random.Next(1, 100) > 50 ? EnumEducation.Primary : EnumEducation.Middel
});
AutoItems.Insert(0, foo);
if (AutoItems.Count > 10)
{

View File

@@ -1,65 +0,0 @@
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Website: https://www.blazor.zone or https://argozhang.github.io/
using BootstrapBlazor.Components;
using BootstrapBlazor.Shared.Pages.Components;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace BootstrapBlazor.Shared.Pages
{
/// <summary>
///
/// </summary>
public abstract class TablesBaseColumn : TablesBaseQuery
{
/// <summary>
///
/// </summary>
/// <param name="d"></param>
/// <returns></returns>
protected Task<string> IntFormatter(object? d)
{
var data = (int?)d;
return Task.FromResult(data?.ToString("0.00") ?? "");
}
/// <summary>
///
/// </summary>
/// <param name="items"></param>
protected Task CustomerButton(IEnumerable<Foo> items)
{
var cate = ToastCategory.Information;
var title = "自定义按钮处理方法";
var content = $"通过不同的函数区分按钮处理逻辑,参数 Items 为 Table 组件中选中的行数据集合,当前选择数据 {items.Count()} 条";
ToastService?.Show(new ToastOption()
{
Category = cate,
Title = title,
Content = content
});
return Task.CompletedTask;
}
/// <summary>
///
/// </summary>
/// <param name="item"></param>
protected Task OnRowButtonClick(Foo item)
{
var cate = ToastCategory.Success;
var title = "行内按钮处理方法";
var content = "通过不同的函数区分按钮处理逻辑,参数 Item 为当前行数据";
ToastService?.Show(new ToastOption()
{
Category = cate,
Title = title,
Content = content
});
return Task.CompletedTask;
}
}
}

View File

@@ -1,101 +0,0 @@
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Website: https://www.blazor.zone or https://argozhang.github.io/
using BootstrapBlazor.Components;
using BootstrapBlazor.Shared.Pages.Components;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace BootstrapBlazor.Shared.Pages
{
/// <summary>
///
/// </summary>
public abstract class TablesBaseEdit : TablesBaseQuery
{
private static readonly object _objectLock = new();
/// <summary>
///
/// </summary>
protected List<Foo> EditItems { get; set; } = GenerateItems();
/// <summary>
///
/// </summary>
protected IEnumerable<SelectedItem>? Educations { get; set; }
/// <summary>
/// OnInitialized 方法
/// </summary>
protected override void OnInitialized()
{
base.OnInitialized();
Educations = typeof(EnumEducation).ToSelectList();
}
/// <summary>
///
/// </summary>
/// <param name="options"></param>
/// <returns></returns>
protected Task<QueryData<Foo>> OnEditQueryAsync(QueryPageOptions options) => FooQueryAsync(EditItems, options);
/// <summary>
///
/// </summary>
/// <returns></returns>
protected static Task<Foo> OnAddAsync()
{
return Task.FromResult(new Foo() { DateTime = DateTime.Now });
}
/// <summary>
///
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
protected Task<bool> OnSaveAsync(Foo item)
{
// 增加数据演示代码
if (item.Id == 0)
{
// 演示代码,生产中请根据实际情况考虑是否加锁操作
lock (_objectLock)
{
item.Id = EditItems.Max(i => i.Id) + 1;
EditItems.Add(item);
}
}
else
{
var oldItem = EditItems.FirstOrDefault(i => i.Id == item.Id);
if (oldItem != null)
{
oldItem.Name = item.Name;
oldItem.Address = item.Address;
oldItem.DateTime = item.DateTime;
oldItem.Count = item.Count;
oldItem.Complete = item.Complete;
oldItem.Education = item.Education;
}
}
return Task.FromResult(true);
}
/// <summary>
///
/// </summary>
/// <param name="items"></param>
/// <returns></returns>
protected Task<bool> OnDeleteAsync(IEnumerable<Foo> items)
{
items.ToList().ForEach(i => EditItems.Remove(i));
return Task.FromResult(true);
}
}
}

Some files were not shown because too many files have changed in this diff Show More