mirror of
https://github.com/dotnetcore/Util.git
synced 2026-10-29 11:36:32 +08:00
更新下拉列表组件,支持lambda表达式解析
This commit is contained in:
@@ -395,6 +395,7 @@ https://github.com/dotnetcore/util/
|
||||
- 组件基类 [已发布]
|
||||
- TagHelper基类 [已发布]
|
||||
- 图标 - 集成了Material Design和Font Awesome图标集 [已发布]
|
||||
- 下拉列表 - 基于Material Select组件 [已发布]
|
||||
- 按钮 [开发中]
|
||||
- 文本框 [开发中]
|
||||
- 权限 [待启动]
|
||||
@@ -438,4 +439,5 @@ https://github.com/dotnetcore/util/
|
||||
- 2017年10月29日,更新了加密操作(Util.Helpers.Encrypt,集成了MD5,DES,AES,RSA加密操作)及单元测试。
|
||||
- 2017年10月30日,更新了Url参数生成器(Util.Parameters)及单元测试。
|
||||
- 2017年10月31日,更新了支付宝条码支付操作(Util.Biz.Payments/Alipay)及单元测试。
|
||||
- 2017年11月15日,更新了EF Core调试日志(Util.Datas/Logs)及单元测试。
|
||||
- 2017年11月15日,更新了EF Core调试日志(Util.Datas/Logs)及单元测试。
|
||||
- 2018年1月2日,更新了下拉列表组件(Util.Ui.Angular/Material/Forms)及单元测试。
|
||||
@@ -1,7 +1,10 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Runtime.Serialization;
|
||||
using Util.Applications.Dtos;
|
||||
using Util.Biz.Enums;
|
||||
using Util.Ui.Attributes;
|
||||
|
||||
namespace Donau.Services.Dtos.Customers {
|
||||
/// <summary>
|
||||
@@ -29,17 +32,16 @@ namespace Donau.Services.Dtos.Customers {
|
||||
/// <summary>
|
||||
/// 余额
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "余额不能为空")]
|
||||
[Display( Name = "余额" )]
|
||||
[DataMember]
|
||||
public decimal Balance { get; set; }
|
||||
public string Balance { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 性别
|
||||
/// </summary>
|
||||
[Display( Name = "性别" )]
|
||||
[DataMember]
|
||||
public int? Gender { get; set; }
|
||||
[Model(Ignore = true)]
|
||||
public Gender Gender { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 联系电话
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
@{
|
||||
@model Donau.Services.Dtos.Customers.CustomersDto
|
||||
@{
|
||||
ViewData["Title"] = "Tile";
|
||||
}
|
||||
<div class="toolbar toolbar-detail search-menu" fxLayout="row" fxLayoutAlign="start center">
|
||||
@@ -23,9 +24,9 @@
|
||||
|
||||
|
||||
|
||||
@(Html.Ui().Select().Placeholder( "民族" ).Enum<Util.Biz.Enums.Nation>().Multiple())
|
||||
|
||||
@Html.Ui().Select(t => t.Gender )
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -5,11 +5,11 @@ namespace Util.Ui.Services {
|
||||
/// <summary>
|
||||
/// Ui上下文
|
||||
/// </summary>
|
||||
public interface IContext {
|
||||
public interface IContext<TModel> {
|
||||
/// <summary>
|
||||
/// HtmlHelper
|
||||
/// </summary>
|
||||
IHtmlHelper Helper { get; }
|
||||
IHtmlHelper<TModel> Helper { get; }
|
||||
/// <summary>
|
||||
/// Html编码
|
||||
/// </summary>
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
namespace Util.Ui.Services {
|
||||
/// <summary>
|
||||
/// 组件服务
|
||||
/// </summary>
|
||||
public interface IUiService {
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.Text.Encodings.Web;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Util.Helpers;
|
||||
using Util.Ui.Services;
|
||||
using Util.Ui.Material.Services;
|
||||
|
||||
namespace Util.Ui.Extensions {
|
||||
/// <summary>
|
||||
@@ -12,8 +12,8 @@ namespace Util.Ui.Extensions {
|
||||
/// Angular组件服务
|
||||
/// </summary>
|
||||
/// <param name="helper">HtmlHelper</param>
|
||||
public static IUiService Ui( this IHtmlHelper helper ) {
|
||||
return new UiService( helper,Ioc.Create<HtmlEncoder>() );
|
||||
public static IUiService<TModel> Ui<TModel>( this IHtmlHelper<TModel> helper ) {
|
||||
return new UiService<TModel>( helper, Ioc.Create<HtmlEncoder>() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using Util.Ui.Components;
|
||||
using Util.Ui.Material.Buttons;
|
||||
using Util.Ui.Material.Forms;
|
||||
using Util.Ui.Material.Icons;
|
||||
using Util.Ui.Material.Services;
|
||||
using Util.Ui.Services;
|
||||
|
||||
namespace Util.Ui.Extensions {
|
||||
@@ -14,7 +15,7 @@ namespace Util.Ui.Extensions {
|
||||
/// 图标
|
||||
/// </summary>
|
||||
/// <param name="service">组件服务</param>
|
||||
public static IIcon Icon( this IUiService service ) {
|
||||
public static IIcon Icon<TModel>( this IUiService<TModel> service ) {
|
||||
return new Icon();
|
||||
}
|
||||
|
||||
@@ -22,7 +23,7 @@ namespace Util.Ui.Extensions {
|
||||
/// 下拉列表
|
||||
/// </summary>
|
||||
/// <param name="service">组件服务</param>
|
||||
public static ISelect Select( this IUiService service ) {
|
||||
public static ISelect Select<TModel>( this IUiService<TModel> service ) {
|
||||
return new Select();
|
||||
}
|
||||
|
||||
@@ -31,7 +32,7 @@ namespace Util.Ui.Extensions {
|
||||
/// </summary>
|
||||
/// <param name="service">组件服务</param>
|
||||
/// <param name="text">文本</param>
|
||||
public static Util.Ui.Material.Buttons.IButton Button( this IUiService service,string text ) {
|
||||
public static Util.Ui.Material.Buttons.IButton Button<TModel>( this IUiService<TModel> service, string text ) {
|
||||
return new Button().Text( text );
|
||||
}
|
||||
|
||||
@@ -39,7 +40,7 @@ namespace Util.Ui.Extensions {
|
||||
/// 文本框
|
||||
/// </summary>
|
||||
/// <param name="service">组件服务</param>
|
||||
public static ITextBox TextBox( this IUiService service ) {
|
||||
public static ITextBox TextBox<TModel>( this IUiService<TModel> service ) {
|
||||
return new TextBox();
|
||||
}
|
||||
|
||||
@@ -47,8 +48,8 @@ namespace Util.Ui.Extensions {
|
||||
/// 表单
|
||||
/// </summary>
|
||||
/// <param name="service">组件服务</param>
|
||||
public static IForm Form( this IUiService service ) {
|
||||
if( !( service is IContext context ))
|
||||
public static IForm Form<TModel>( this IUiService<TModel> service ) {
|
||||
if( !( service is IContext<TModel> context ) )
|
||||
throw new NotImplementedException( "组件服务必须实现Util.Ui.Services.IContext" );
|
||||
return new Form( context.Helper.ViewContext.Writer, context.Encoder );
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Util.Ui.Material.Extensions {
|
||||
/// </summary>
|
||||
public static partial class Extensions {
|
||||
/// <summary>
|
||||
/// 设置占位符
|
||||
/// 设置占位提示符
|
||||
/// </summary>
|
||||
/// <typeparam name="TComponent">组件类型</typeparam>
|
||||
/// <param name="component">组件实例</param>
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
using Util.Ui.Components.Internal;
|
||||
using Util.Ui.Configs;
|
||||
|
||||
namespace Util.Ui.Extensions {
|
||||
namespace Util.Ui.Material.Extensions {
|
||||
/// <summary>
|
||||
/// 文本框扩展
|
||||
/// </summary>
|
||||
@@ -0,0 +1,84 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using Util.Helpers;
|
||||
using Util.Ui.Extensions;
|
||||
using Util.Ui.Internal;
|
||||
using Util.Ui.Material.Extensions;
|
||||
|
||||
namespace Util.Ui.Material.Forms.Models {
|
||||
/// <summary>
|
||||
/// 模型下拉列表
|
||||
/// </summary>
|
||||
/// <typeparam name="TModel">模型类型</typeparam>
|
||||
/// <typeparam name="TProperty">属性类型</typeparam>
|
||||
public class ModelSelect<TModel, TProperty> : Select {
|
||||
/// <summary>
|
||||
/// 初始化模型下拉列表
|
||||
/// </summary>
|
||||
/// <param name="expression">属性表达式</param>
|
||||
public ModelSelect( Expression<Func<TModel, TProperty>> expression ) {
|
||||
if( expression == null )
|
||||
return;
|
||||
_expression = expression;
|
||||
_memberInfo = Lambda.GetMember( _expression );
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 属性表达式
|
||||
/// </summary>
|
||||
private readonly Expression<Func<TModel, TProperty>> _expression;
|
||||
/// <summary>
|
||||
/// 成员
|
||||
/// </summary>
|
||||
private readonly MemberInfo _memberInfo;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化
|
||||
/// </summary>
|
||||
private void Init() {
|
||||
InitModel();
|
||||
InitPlaceholder();
|
||||
InitType();
|
||||
InitRequired();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化模型绑定
|
||||
/// </summary>
|
||||
private void InitModel() {
|
||||
var model = Helper.GetModel( _expression );
|
||||
if ( string.IsNullOrWhiteSpace( model ) )
|
||||
return;
|
||||
this.Model( model );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化占位提示符
|
||||
/// </summary>
|
||||
private void InitPlaceholder() {
|
||||
this.Placeholder( Reflection.GetDisplayNameOrDescription( _memberInfo ) );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据类型初始化
|
||||
/// </summary>
|
||||
private void InitType() {
|
||||
if( Reflection.IsBool( _memberInfo ) )
|
||||
this.Bool();
|
||||
else if( Reflection.IsEnum( _memberInfo ) )
|
||||
Enum<TProperty>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化必填项验证
|
||||
/// </summary>
|
||||
private void InitRequired() {
|
||||
var attribute = Lambda.GetAttribute<RequiredAttribute>( _expression );
|
||||
if( attribute != null )
|
||||
this.Required( attribute.ErrorMessage );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -91,7 +91,7 @@ namespace Util.Ui.Material.Forms.Renders {
|
||||
/// 配置模型绑定
|
||||
/// </summary>
|
||||
private void ConfigModel( SelectWrapperBuilder builder ) {
|
||||
builder.AddAttribute( "[(model)]", _config.GetBoolValue( UiConst.Model ) );
|
||||
builder.AddAttribute( "[(model)]", _config.GetValue( UiConst.Model ) );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Linq.Expressions;
|
||||
using Util.Ui.Components;
|
||||
|
||||
namespace Util.Ui.Material.Services {
|
||||
/// <summary>
|
||||
/// 组件服务
|
||||
/// </summary>
|
||||
public interface IUiService<TModel> {
|
||||
/// <summary>
|
||||
/// 下拉列表
|
||||
/// </summary>
|
||||
/// <typeparam name="TProperty">属性类型</typeparam>
|
||||
/// <param name="expression">属性表达式</param>
|
||||
ISelect Select<TProperty>( Expression<Func<TModel, TProperty>> expression );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text.Encodings.Web;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Util.Ui.Components;
|
||||
using Util.Ui.Material.Forms.Models;
|
||||
using Util.Ui.Services;
|
||||
|
||||
namespace Util.Ui.Material.Services {
|
||||
/// <summary>
|
||||
/// 组件服务
|
||||
/// </summary>
|
||||
/// <typeparam name="TModel">模型类型</typeparam>
|
||||
public class UiService<TModel> : UiServiceBase<TModel>, IUiService<TModel> {
|
||||
/// <summary>
|
||||
/// 初始化组件服务
|
||||
/// </summary>
|
||||
/// <param name="helper">HtmlHelper</param>
|
||||
/// <param name="encoder">Html编码</param>
|
||||
public UiService( IHtmlHelper<TModel> helper, HtmlEncoder encoder ) : base( helper, encoder ) {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 下拉列表
|
||||
/// </summary>
|
||||
/// <typeparam name="TProperty">属性类型</typeparam>
|
||||
/// <param name="expression">属性表达式</param>
|
||||
public ISelect Select<TProperty>( Expression<Func<TModel, TProperty>> expression ) {
|
||||
return new ModelSelect<TModel, TProperty>( expression );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
|
||||
namespace Util.Ui.Attributes {
|
||||
/// <summary>
|
||||
/// 模型绑定
|
||||
/// </summary>
|
||||
[AttributeUsage( AttributeTargets.Class | AttributeTargets.Property )]
|
||||
public class ModelAttribute : Attribute {
|
||||
/// <summary>
|
||||
/// 初始化模型绑定
|
||||
/// </summary>
|
||||
/// <param name="model">模型</param>
|
||||
public ModelAttribute( string model = "" ) {
|
||||
Model = model;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 模型
|
||||
/// </summary>
|
||||
public string Model { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 忽略模型绑定,设置为true则不设置模型绑定
|
||||
/// </summary>
|
||||
public bool Ignore { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ namespace Util.Ui.Extensions {
|
||||
/// </summary>
|
||||
public static partial class Extensions {
|
||||
/// <summary>
|
||||
/// 设置占位符
|
||||
/// 设置占位提示符
|
||||
/// </summary>
|
||||
/// <typeparam name="TComponent">组件类型</typeparam>
|
||||
/// <param name="component">组件实例</param>
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using Util.Helpers;
|
||||
using Util.Ui.Attributes;
|
||||
|
||||
namespace Util.Ui.Internal {
|
||||
/// <summary>
|
||||
/// 辅助操作
|
||||
/// </summary>
|
||||
public static class Helper {
|
||||
/// <summary>
|
||||
/// 获取模型
|
||||
/// </summary>
|
||||
/// <typeparam name="TModel">模型类型</typeparam>
|
||||
/// <typeparam name="TProperty">属性类型</typeparam>
|
||||
public static string GetModel<TModel, TProperty>( Expression<Func<TModel, TProperty>> expression ) {
|
||||
var modelName = Util.Helpers.String.FirstLowerCase( GetModelName<TModel>() );
|
||||
var propertyName = Util.Helpers.String.FirstLowerCase( GetPropertyName( expression ) );
|
||||
if ( string.IsNullOrWhiteSpace( modelName ) || string.IsNullOrWhiteSpace( propertyName ) )
|
||||
return string.Empty;
|
||||
return $"{modelName}.{propertyName}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取模型名称
|
||||
/// </summary>
|
||||
private static string GetModelName<TModel>() {
|
||||
Type type = Common.GetType<TModel>();
|
||||
if ( type.GetCustomAttribute<ModelAttribute>() is ModelAttribute attribute ) {
|
||||
return attribute.Ignore ? string.Empty : attribute.Model;
|
||||
}
|
||||
return typeof( TModel ).Name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取属性名称
|
||||
/// </summary>
|
||||
private static string GetPropertyName<TModel, TProperty>( Expression<Func<TModel, TProperty>> expression ) {
|
||||
var attribute = Lambda.GetAttribute<ModelAttribute>( expression );
|
||||
return attribute == null ? Lambda.GetName( expression ) : attribute.Ignore ? string.Empty : attribute.Model; ;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,13 +5,13 @@ namespace Util.Ui.Services {
|
||||
/// <summary>
|
||||
/// 组件服务
|
||||
/// </summary>
|
||||
public class UiService : IUiService, IContext {
|
||||
public class UiServiceBase<TModel> : IContext<TModel> {
|
||||
/// <summary>
|
||||
/// 初始化组件服务
|
||||
/// </summary>
|
||||
/// <param name="helper">HtmlHelper</param>
|
||||
/// <param name="encoder">Html编码</param>
|
||||
public UiService( IHtmlHelper helper, HtmlEncoder encoder) {
|
||||
public UiServiceBase( IHtmlHelper<TModel> helper, HtmlEncoder encoder ) {
|
||||
Helper = helper;
|
||||
Encoder = encoder;
|
||||
}
|
||||
@@ -19,7 +19,7 @@ namespace Util.Ui.Services {
|
||||
/// <summary>
|
||||
/// HtmlHelper
|
||||
/// </summary>
|
||||
public IHtmlHelper Helper { get; }
|
||||
public IHtmlHelper<TModel> Helper { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Html编码
|
||||
@@ -81,7 +81,7 @@ namespace Util.Helpers {
|
||||
/// <summary>
|
||||
/// 获取属性显示名称或描述,使用DisplayNameAttribute或DisplayAttribute设置显示名称,使用DescriptionAttribute设置描述
|
||||
/// </summary>
|
||||
public static string GetDisplayNameOrDescription( PropertyInfo member ) {
|
||||
public static string GetDisplayNameOrDescription( MemberInfo member ) {
|
||||
var result = GetDisplayName( member );
|
||||
return string.IsNullOrWhiteSpace( result ) ? GetDescription( member ) : result;
|
||||
}
|
||||
@@ -89,7 +89,7 @@ namespace Util.Helpers {
|
||||
/// <summary>
|
||||
/// 获取类型成员显示名称,使用DisplayNameAttribute或DisplayAttribute设置显示名称
|
||||
/// </summary>
|
||||
private static string GetDisplayName( PropertyInfo member ) {
|
||||
private static string GetDisplayName( MemberInfo member ) {
|
||||
if( member == null )
|
||||
return string.Empty;
|
||||
if( member.GetCustomAttribute( typeof( DisplayNameAttribute ) ) is DisplayNameAttribute displayNameAttribute )
|
||||
@@ -147,11 +147,7 @@ namespace Util.Helpers {
|
||||
/// 是否布尔类型
|
||||
/// </summary>
|
||||
private static bool IsBool( PropertyInfo property ) {
|
||||
if( property.PropertyType == typeof( bool ) )
|
||||
return true;
|
||||
if( property.PropertyType == typeof( bool? ) )
|
||||
return true;
|
||||
return false;
|
||||
return property.PropertyType == typeof( bool ) || property.PropertyType == typeof( bool? );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -123,5 +123,19 @@ namespace Util.Helpers {
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region FirstLowerCase(首字母小写)
|
||||
|
||||
/// <summary>
|
||||
/// 首字母小写
|
||||
/// </summary>
|
||||
/// <param name="value">值</param>
|
||||
public static string FirstLowerCase( string value ) {
|
||||
if ( string.IsNullOrWhiteSpace( value ) )
|
||||
return string.Empty;
|
||||
return $"{value.Substring( 0, 1 ).ToLower()}{value.Substring( 1 )}";
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,8 +25,8 @@ namespace Util.Tests.Helpers {
|
||||
new Guid( "83B0233C-A24F-49FD-8083-1337209EBC9A" ),
|
||||
new Guid( "EAB523C6-2FE7-47BE-89D5-C6D440C3033A" )
|
||||
};
|
||||
Assert.Equal( "83B0233C-A24F-49FD-8083-1337209EBC9A,EAB523C6-2FE7-47BE-89D5-C6D440C3033A".ToLower(),Util.Helpers.String.Join( list ) );
|
||||
Assert.Equal( "'83B0233C-A24F-49FD-8083-1337209EBC9A','EAB523C6-2FE7-47BE-89D5-C6D440C3033A'".ToLower(),Util.Helpers.String.Join( list, "'" ) );
|
||||
Assert.Equal( "83B0233C-A24F-49FD-8083-1337209EBC9A,EAB523C6-2FE7-47BE-89D5-C6D440C3033A".ToLower(), Util.Helpers.String.Join( list ) );
|
||||
Assert.Equal( "'83B0233C-A24F-49FD-8083-1337209EBC9A','EAB523C6-2FE7-47BE-89D5-C6D440C3033A'".ToLower(), Util.Helpers.String.Join( list, "'" ) );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -42,5 +42,21 @@ namespace Util.Tests.Helpers {
|
||||
public void TestPinYin( string input, string result ) {
|
||||
Assert.Equal( result, Util.Helpers.String.PinYin( input ) );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 首字母小写
|
||||
/// </summary>
|
||||
[Theory]
|
||||
[InlineData( null, "" )]
|
||||
[InlineData( "", "" )]
|
||||
[InlineData( " ", "" )]
|
||||
[InlineData( "a", "a" )]
|
||||
[InlineData( "A", "a" )]
|
||||
[InlineData( "Ab", "ab" )]
|
||||
[InlineData( "AB", "aB" )]
|
||||
[InlineData( "Abc", "abc" )]
|
||||
public void TestFirstLowerCase( string value, string result ) {
|
||||
Assert.Equal( result, Util.Helpers.String.FirstLowerCase( value ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.IO;
|
||||
using System.Text.Encodings.Web;
|
||||
using Util.Helpers;
|
||||
using Util.Ui.Extensions;
|
||||
using Util.Ui.Material.Extensions;
|
||||
using Util.Ui.Material.Forms;
|
||||
using Util.Webs;
|
||||
using Xunit;
|
||||
|
||||
Reference in New Issue
Block a user