如何在同一ViewModel中为同类型属性实例设置不同标签?
解决方案
当然可行,给你两个直接落地的方案,不用在每个视图重复配置标签:
方案1:子类继承+重写属性加DisplayName(最省心)
既然Tool和Hardware都是基于SubPropertiesVM的不同实例,直接给它们做子类,在子类里重写Description属性并单独加[DisplayName]特性就行,这样所有用MyViewModel的视图都会自动读取对应标签:
修改后的视图模型代码
// 基类保持通用,Description设为virtual public class SubPropertiesVM { public int ID { get; set; } public virtual string Description { get; set; } public string SubPropertyLabel { get; set; } } // Tool专属子类,给Description设置自定义标签 public class ToolVM : SubPropertiesVM { [DisplayName("Tool details")] public override string Description { get; set; } } // Hardware专属子类,设置另一个标签 public class HardwareVM : SubPropertiesVM { [DisplayName("Hardware details")] public override string Description { get; set; } } // 主视图模型改用子类实例 public class MyViewModel { public ToolVM Tool { get; set; } = new ToolVM(); public HardwareVM Hardware { get; set; } = new HardwareVM(); }
视图代码完全不用改,@MyHelperFor(c => c.Tool.Description)会自动读取ToolVM里的DisplayName,Hardware同理,所有使用这个ViewModel的视图都会统一显示正确标签。
方案2:自定义显示元数据提供器(更灵活)
如果不想创建子类,可以实现IDisplayMetadataProvider接口,自定义逻辑根据父属性名称(比如Tool或Hardware)来动态设置Description的标签:
步骤1:写自定义元数据提供器
public class DynamicDisplayNameProvider : IDisplayMetadataProvider { public void CreateDisplayMetadata(DisplayMetadataProviderContext context) { // 判断当前属性是SubPropertiesVM的Description,且父属性是Tool或Hardware if (context.PropertyName == nameof(SubPropertiesVM.Description) && context.ContainerType != null) { var parentPropertyName = context.ContainerType.Name switch { nameof(MyViewModel) => context.PropertyAttributes .OfType<ParentPropertyAttribute>() .FirstOrDefault()?.ParentName, _ => null }; if (parentPropertyName == nameof(MyViewModel.Tool)) { context.DisplayMetadata.DisplayName = () => "Tool details"; } else if (parentPropertyName == nameof(MyViewModel.Hardware)) { context.DisplayMetadata.DisplayName = () => "Hardware details"; } } } } // 辅助特性,标记父属性名称 [AttributeUsage(AttributeTargets.Property)] public class ParentPropertyAttribute : Attribute { public string ParentName { get; } public ParentPropertyAttribute(string parentName) => ParentName = parentName; }
步骤2:在MyViewModel里标记属性
public class MyViewModel { [ParentProperty(nameof(Tool))] public SubPropertiesVM Tool { get; set; } = new SubPropertiesVM(); [ParentProperty(nameof(Hardware))] public SubPropertiesVM Hardware { get; set; } = new SubPropertiesVM(); }
步骤3:注册元数据提供器
在Startup/Program.cs里添加:
builder.Services.AddControllersWithViews() .AddMvcOptions(options => { options.ModelMetadataDetailsProviders.Add(new DynamicDisplayNameProvider()); });
这个方案适合需要更复杂动态逻辑的场景,比如标签要从配置读取,但方案1已经能满足你的基本需求,更简单易维护。
内容的提问来源于stack exchange,提问作者Hayee
相关产品推荐
相关产品推荐

