如何在不使用“DisplayNameAttribute”的情况下更改 ViewModel 显示名称?

2023-11-29

我想直接更改(ViewModel 的)某些属性的显示名称,而不使用[DisplayName("prop name")]。这应该发生直接在控制器内部在返回视图之前,或者在 ViewModel 类本身内部.

我不想更改视图中的任何内容,也不想使用任何数据注释。我怎样才能做到这一点?

有没有流畅的语法可以做到这一点?

我在用:ASP.NET核心2.0

数据注释的问题是我想在运行时获取我的显示名称(而数据注释是预编译的)。

UPDATE:

问这个问题的主要原因是找到一种方法来包裹IStringLocalizer特别是本地化数据注释时的行为。接受的答案很好地解释了这一点的基础知识。


@Tseng,抱歉,我应该说得更清楚,我的意思是我们应该使用命名约定或共享资源。但不是两者兼而有之,我在很多情况下都有很多共享资源和许多特定于 ViewModel 的字符串(所以是混合的)。这是 .Net Core 本地化解决方案无法实现的。

如果您唯一担心的是您能否确定是否选择一个或多个资源文件,则可以轻松配置。我不得不深入研究一下源代码,这似乎是可能的。

正如我们所看到的here the localizer由配置中定义的工厂决定

if (_stringLocalizerFactory != null && _localizationOptions.DataAnnotationLocalizerProvider != null)
{
    localizer = _localizationOptions.DataAnnotationLocalizerProvider(containerType, _stringLocalizerFactory);
}

whereas _localizationOptions is MvcDataAnnotationsLocalizationOptions.

默认实现MvcDataAnnotationsLocalizationOptions is here:

/// <inheritdoc />
public void Configure(MvcDataAnnotationsLocalizationOptions options)
{
    if (options == null)
    {
        throw new ArgumentNullException(nameof(options));
    }

    options.DataAnnotationLocalizerProvider = (modelType, stringLocalizerFactory) =>
        stringLocalizerFactory.Create(modelType);
}

因此它默认使用每个模型的资源。

你可以将其更改为SharedResource如果您愿意,可以保存所有数据注释的文件,并在您的文件中包含以下内容Startup.ConfigureServices(未经测试,但应该有效):

services.AddMvc()
    .AddDataAnnotationsLocalization(options =>
    {
        options.DataAnnotationLocalizerProvider = (type, factory) =>
            factory.Create(typeof(SharedResource));
    });

这将有效地忽略传递的类型并始终返回共享字符串本地化程序。

当然,您可以在其中添加任何逻辑,并根据每种类型的情况决定要使用哪个本地化程序。

Edit

如果这还不够,您可以实现自己的自定义IDisplayMetadataProvider它按照你想要的方式处理它。但使用DisplayAttribute实际上应该足够了。DisplayAttribute有额外的参数允许您定义资源类型。

[Display(Name = "StringToLocalize", ResourceType = typeof(SharedResource))]

随着ResourceType您可以选择用于查找本地化的类(以及资源​​文件名)。

编辑2:使用包裹IStringLocalizer回退到每个视图模型资源

更优雅的解决方案涉及使用上面的MvcDataAnnotationsLocalizationOptions选项文件返回您自己的IStringLocalizer它会查看一个资源文件并返回到另一个资源文件。

public class DataAnnotationStringLocalizer : IStringLocalizer
{
    private readonly IStringLocalizer primaryLocalizer;
    private readonly IStringLocalizer fallbackLocalizer;

    public DataAnnotationStringLocalizer(IStringLocalizer primaryLocalizer, IStringLocalizer fallbackLocalizer)
    {
        this.primaryLocalizer = primaryLocalizer ?? throw new ArgumentNullException(nameof(primaryLocalizer));
        this.fallbackLocalizer = fallbackLocalizer ?? throw new ArgumentNullException(nameof(fallbackLocalizer));
    }

    public LocalizedString this[string name]
    {
        get
        {
            LocalizedString localizedString = primaryLocalizer[name];
            if (localizedString.ResourceNotFound)
            {
                localizedString = fallbackLocalizer[name];
            }

            return localizedString;
        }
    }

    public LocalizedString this[string name, params object[] arguments]
    {
        get
        {
            LocalizedString localizedString = primaryLocalizer[name, arguments];
            if (localizedString.ResourceNotFound)
            {
                localizedString = fallbackLocalizer[name, arguments];
            }

            return localizedString;
        }
    }

    public IEnumerable<LocalizedString> GetAllStrings(bool includeParentCultures)
        => primaryLocalizer.GetAllStrings(includeParentCultures).Concat(fallbackLocalizer.GetAllStrings(includeParentCultures));

    public IStringLocalizer WithCulture(CultureInfo culture)
        => new DataAnnotationStringLocalizer(primaryLocalizer.WithCulture(culture), fallbackLocalizer.WithCulture(culture));
}

并有以下选项

services.AddMvc()
    .AddDataAnnotationsLocalization(options =>
    {
        options.DataAnnotationLocalizerProvider = (type, factory) =>
        {
            return new DataAnnotationStringLocalizer(
                factory?.Create(typeof(SharedResource)),
                factory?.Create(type)
            );
        };
    });

现在,首先从共享资源解析该字符串,如果在那里找不到该字符串,它将从视图模型类型(传递给工厂方法的类型参数)解析它。

如果您不喜欢该逻辑并且希望它首先查看视图模型资源文件,则只需将顺序更改为

services.AddMvc()
    .AddDataAnnotationsLocalization(options =>
    {
        options.DataAnnotationLocalizerProvider = (type, factory) =>
        {
            return new DataAnnotationStringLocalizer(
                factory?.Create(type),
                factory?.Create(typeof(SharedResource))
            );
        }
    });

现在,视图模型是主要解析器,共享资源是辅助解析器

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在不使用“DisplayNameAttribute”的情况下更改 ViewModel 显示名称? 的相关文章

随机推荐

  • Express.js 无效的 JSON GET 请求

    在编写 API 时 我遇到了一个非常棘手的错误 当我尝试执行res send INSERT JSON 带有 Content Type 标头application json 大多数 AJAX 的默认设置 我得到一个invalid json错误
  • 使用命令将单词与 vim 中的指定列对齐

    如何将整个文件中的单词移动或移动到指定列 例如如下所示 前 123 ABC 112 XYZS 15925 asdf 1111 25asd 1 qwer After 123 ABC 112 XYZS 15925 asdf 1111 25asd
  • 在一组两种可能性中选择唯一的行

    问题本身很简单 但我无法找出在一个查询中完成此任务的解决方案 这是我对问题的 抽象 以便进行更简单的解释 我将保留我最初的解释 但这里有一组示例数据和我期望的结果 好的 这是一些示例数据 我用空行分隔对 Key Col Together t
  • JQuery 表单验证不适用于新创建的元素

    我在使用 Jquery 验证插件时遇到了一些问题 想知道是否有人可以提供帮助 目前 该插件适用于当前页面上的任何表单元素 addRelease validate submitHandler function form form submit
  • 如何在 XSD 中引用全局类型?

    如何实现对 simpleType 的 XSD 内部引用 我遇到了您在下图中看到的错误 XSD
  • Delphi中OnKeyDown的问题

    我正在与德尔福合作 我想跟踪按下了哪个键 我正在使用 TForm 的 KeyDown 事件 它工作正常 但问题是 如果我按小写字母 但它会给出该字母的大写字母 如何识别按下的按键是小写还是大写 如果您想跟踪字母数字键 那么您应该使用KeyP
  • 将 Facebook 登录应用程序与 Facebook 粉丝页面链接有什么优势?

    我正在创建一个电子商务网站 我将支持 FB 登录 我也会有一个FB粉丝专页 在支持 facebook 登录应用程序的同时 可以选择将 FB 页面附加到登录应用程序 App gt app name gt 应用程序详细信息 gt 联系信息 gt
  • iOS静默推送通知已取消

    在我的应用程序中 我使用静默推送通知来定期通信 但我遇到了麻烦 因为我在未启动应用程序时收到的静默推送通知未被处理 操作系统版本为iOS12 我正在使用 FCM 发送推送通知 有人有同样的问题吗 以下是您收到静默推送通知时的控制台日志 10
  • iOS 6 MPMoviePlayerViewController 和 PresentMoviePlayerViewControllerAnimated Rotation

    在以前的 iOS 版本中 我们的视频会自动旋转 但在 iOS 6 中不再是这种情况 我知道 PresentMoviePlayerViewControllerAnimated 以前是设计用于执行此操作的 但是我如何告诉 MPMoviePlay
  • Android:如何检测双 SD 卡[重复]

    这个问题在这里已经有答案了 有什么方法可以识别设备中是否有两张 SD 卡 Edit 我发现目前无法区分内部存储和真正的外部SD卡 在某些设备 例如 Samsung Galaxy Tab 7 英寸 中 系统将内部存储 通常为 16GB 视为外
  • Android:MediaPlayer AUDIOFOCUS_LOSS 和 setOnErrorListener() 问题

    我正在创建一个音乐播放器应用程序 我正在检查我的应用程序是否丢失 AudioFocus 然后播放将停止 但这提出了一个问题 当我播放一首曲目时 然后停止它 然后再次播放一首曲目 switch case AudioManager AUDIOF
  • String.equals() 是如何工作的

    我一直在尝试了解一些 API 方法是如何工作的 下面是 java lang String 类的 equals 方法的片段 有人可以告诉我代码实际上是如何比较两个字符串的吗 我明白了计数的重要性 但是偏移量意味着什么 这些变量如何获取值 就像
  • 从 Wikipedia API 获取名人

    我正在尝试从 Wikipedia API 中获取还活着的人 但我还不知道该怎么做 I found 这个问题这和我的一样 据我所知 唯一的方法是搜索只有birth date参数的人 我实际上该怎么做 例如 如果我想搜索 罗纳尔多 我应该得到所
  • Ionic V5 在 Safari 上出现 Angular 组件问题

    我遇到了 Ionic PWA 应用程序在 Safari 上针对以下 UI 组件的点击问题 离子无线电 离子选择 离子菜单 当您单击单选按钮组件 https ionicframework com docs api radio 1 时 您可以看
  • Oracle 中不带 FROM 子句的选择

    in SQL服务器可以在不引用表的情况下执行 SELECT 就像是 Select 1 2 3 my dummy string As Oracle不允许没有 FROM 的 SELECT 我使用双表进行此类操作 就像是 Select 1 2 3
  • RadioGroup 允许选择多个RadioButton

    我有一个在 XML 中定义的 RadioGroup 它有两个 RadioButton 但是 我需要将标签显示在按钮本身的左侧 标签左对齐 按钮右对齐 为此 我使用了包含 TextView 和 RadioButton 的relativelay
  • 绝对位置元素在静态父级中的行为究竟如何

    我问这个问题是因为昨天我必须设置几个 div 的样式 如下所示thisJSFiddle 示例 对我来说最棘手的部分是定位 div 就从 div 但保持它们顶部对齐 我也想要边界 div 走出它的父div 因此 经过一些研究 我是 CSS 初
  • 如何格式化要使用 arrayWithContentsOfFile 读取的文本文件

    我有几个大的单词列表 我已经将它们加载到代码中 如下所示 NSArray dict3 NSArray alloc initWithObjects abled about above absurd absurdity 但现在它实际上奇怪地导致
  • Actionscript3 阿尔法掩蔽?

    我试图在谷歌地图应用程序上应用聚光灯效果 具体来说 我画了一个跟随鼠标的圆圈 并将其设置为地图上的遮罩 问题是只有圆圈内的地图区域显示出来 我知道这就是蒙版应该看起来的样子 但是有没有办法使圆圈外的区域成为某种半透明 以便其下方的地图也可以
  • 如何在不使用“DisplayNameAttribute”的情况下更改 ViewModel 显示名称?

    我想直接更改 ViewModel 的 某些属性的显示名称 而不使用 DisplayName prop name 这应该发生直接在控制器内部在返回视图之前 或者在 ViewModel 类本身内部 我不想更改视图中的任何内容 也不想使用任何数据