Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-core/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 设置/更改控制器/视图组件中属性的显示(Name=”“)属性_C#_Asp.net Core_Data Annotations_Displayname Attribute - Fatal编程技术网

C# 设置/更改控制器/视图组件中属性的显示(Name=”“)属性

C# 设置/更改控制器/视图组件中属性的显示(Name=”“)属性,c#,asp.net-core,data-annotations,displayname-attribute,C#,Asp.net Core,Data Annotations,Displayname Attribute,根据2010年的回答,关于mvc-2,这是不可能的。那么现在,在asp.net-core 2.2中呢 我的用例: 我有一个BaseViewModel,它被两个视图使用:用户的TableView和管理员的TableManagementView。BaseViewModel由ViewComponent调用。以下是一些示例: BaseViewModel: public class BaseViewModel { [Display(Name = "Comment") public stri

根据2010年的回答,关于mvc-2,这是不可能的。那么现在,在asp.net-core 2.2中呢

我的用例:

我有一个BaseViewModel,它被两个视图使用:用户的TableView和管理员的TableManagementView。BaseViewModel由ViewComponent调用。以下是一些示例:

BaseViewModel:

public class BaseViewModel {
    [Display(Name = "Comment")
    public string UserComment { get; set; }
}
TableView:

@await Component.InvokeAsync(nameof(Base), new { myObject = myObject, stringName = "User"})
表管理视图:

@await Component.InvokeAsync(nameof(Base), new { myObject = myObject, stringName = "Admin"})
基数:

BaseViewComponent:

@Html.DisplayNameFor(model => model.UserComment)
BaseViewModel已简化,但还有更多属性。我这样做的原因是为了避免两个表中的代码重复。唯一需要更改的是标签名称

我尝试过反思,但没有成功:

public IViewComponentResult Invoke(BaseViewModel myObject, string invokingView)
    {
        MemberInfo property = typeof(BaseViewModel).GetProperty("UserComment");
        property.GetCustomAttributes(typeof(DisplayAttribute)).Cast<DisplayAttribute>().Single().Name = "test";

        return View("BaseViewComponent", myObject);
    }
名称不会更改,并保留初始设置的注释


如果无法以编程方式设置属性名,我还有什么其他解决方案?我正在考虑ViewBag/ViewData或TempData,但这个解决方案对我不感兴趣。这其中的利弊是什么?

扩展我留下的评论,解决这个问题的一种方法是将BaseViewModel作为一个抽象类,并从中派生出具体的类。所以UserViewModel和AdminViewModel。这两个具体的类将成为TableView和TableManagementView的模型,并负责告诉外界如何标记字段

基类除了普通字段之外还有两个主要方面:一个包含标签的抽象字典和一个从列表中获取标签的方法:string GetLabelstring propName。比如说:

public abstract class BaseViewModel
{
    protected abstract Dictionary<string, string> Labels { get; }

    public string UserComment { get; set; }

    public string GetLabel(string propName)
    {
        if (!Labels.TryGetValue(propName, out var label))
            throw new KeyNotFoundException($"Label not found for property name: {propName}");

        return label;
    }
}
它们只实现字典并为基类上的每个字段设置适当的文本

接下来,将BaseViewComponent更改为:

视图:

最后,将视图TableView和TableManagementView更改为:

现在,当您导航到TableView时,您将向BaseViewComponent传递一个UserViewModel,它将找出正确的标签。引入新字段将要求您更改viewmodels,并在字典中添加新条目


这并不完美,但我认为这是解决问题的好办法。到目前为止,我还不是一个MVC专家,所以也许其他人也能想出一个更自然的方法来做到这一点。我还准备了一个工作示例应用程序,并将其推送到GitHub。您可以在这里查看:。希望能有所帮助。

如果您的对象具有具体类型baseViewModel是抽象的,您有UserViewModel和AdminViewModel,并且都实现了一个为您提供正确标签的界面,该解决方案又优雅又漂亮。我喜欢你抽象事物和使用字典的方式。我从来没有想过要这样使用它。我一直认为viewmodels是独立的容器。将派生类密封起来或将它们放在同一名称空间中有什么特别的原因吗?或者这只是为了让样本更容易阅读?很高兴它很有用!是的,派生类应该有单独的文件,我只是为了方便而把它们放在一起。它们不必被密封,但我喜欢这样做是为了表达它们不应该被分类的意图。它们是最终的。
public abstract class BaseViewModel
{
    protected abstract Dictionary<string, string> Labels { get; }

    public string UserComment { get; set; }

    public string GetLabel(string propName)
    {
        if (!Labels.TryGetValue(propName, out var label))
            throw new KeyNotFoundException($"Label not found for property name: {propName}");

        return label;
    }
}
public sealed class UserViewModel : BaseViewModel
{
    protected override Dictionary<string, string> Labels => new Dictionary<string, string>
    {
        { nameof(UserComment), "User label" }
    };
}

public sealed class AdminViewModel : BaseViewModel
{
    protected override Dictionary<string, string> Labels => new Dictionary<string, string>
    {
        { nameof(UserComment), "Admin label" }
    };
}
@model DisplayNameTest.Models.BaseViewModel

<h3>Hello from my View Component</h3>

<!-- Gets the label via the method on the base class -->
<p>@Model.GetLabel(nameof(BaseViewModel.UserComment))</p>

<p>@Model.UserComment)</p>
public IViewComponentResult Invoke(BaseViewModel viewModel)
{
    return View(viewModel);
}
@model WebApp.Models.AdminViewModel

@{
    Layout = null;
}

<h1>Admin View</h1>
<div>
    @await Component.InvokeAsync("Base", Model)
</div>
public IActionResult Index()
{
    var adminViewModel = new AdminViewModel { UserComment = "some comment from admin" };
    return View(adminViewModel);
}