为了账号安全,请及时绑定邮箱和手机立即绑定

在 Controller/ViewComponent 中设置/更改属性的 Display

在 Controller/ViewComponent 中设置/更改属性的 Display

C#
陪伴而非守候 2022-10-23 16:14:34
根据2010 年的这个答案,关于 mvc-2,这是不可能的。现在,在 asp.net-core 2.2 中呢?我的用例:我有一个BaseViewModel被 2 个视图使用的视图:(TableView对于用户)和TableManagentView(对于管理员)。由BaseViewModela 调用ViewComponent。以下是一些示例:基础视图模型:public class BaseViewModel {    [Display(Name = "Comment")    public string UserComment { get; set; }}表视图:@await Component.InvokeAsync(nameof(Base), new { myObject = myObject, stringName = "User"})表管理视图:@await Component.InvokeAsync(nameof(Base), new { myObject = myObject, stringName = "Admin"})根据:public class Base : ViewComponent{    public IViewComponentResult Invoke(BaseViewModel myObjet, string invokingView)    {        // here i want to do something like that        if (invokingView == "User") {            myObject.UserComment.SetDisplayName("My Comment");        }         if (invokingView == "Admin") {            myObject.UserComment.SetDisplayName("User's Comment");        }        return View("BaseViewComponent", myObject);    }}基本视图组件:@Html.DisplayNameFor(model => model.UserComment)被BaseViewModel简化了,但还有更多的属性。我想这样做的原因是避免两个表中的代码重复。唯一应该改变的是标签名称。我试过了reflection,但没有成功: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);    }Name不会改变并保持初始"Comment"设置。如果无法以编程方式设置属性名称,我还有哪些其他解决方案?我正在考虑ViewBag/ViewDataor TempData,但这个解决方案对我没有吸引力。这样做的利弊是什么?
查看完整描述

1 回答

?
慕的地8271018

TA贡献1796条经验 获得超4个赞

扩展我留下的评论,你可以解决这个问题的一种方法是让你BaseViewModel成为一个抽象类并拥有从它派生的具体类。所以UserViewModel和AdminViewModel。这两个具体类将成为两者的模型,TableView并将TableManagentView负责告诉“外部世界”如何标记字段。


基类有两个主要方面(除了你的普通字段):一个Dictionary<string, string>包含标签的抽象和一个从列表中获取标签的方法:string GetLabel(string 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;

    }

}

然后创建两个派生类User和Admin:


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" }

    };

}

他们只Dictionary<string, string>为基类上的每个字段实现并设置适当的文本。


接下来,将您的更改BaseViewComponent为:


查看:


@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>

ComponentView 类(现在更简单了)


public IViewComponentResult Invoke(BaseViewModel viewModel)

{

    return View(viewModel);

}

最后,改变你的观点TableView和TableManagentView这个:


@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);

}

现在,当您导航到 时TableView,您会将 a 传递UserViewModel给 the BaseViewComponent,它会找出正确的标签。引入新字段现在需要您更改视图模型,将新条目添加到字典中。


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


查看完整回答
反对 回复 2022-10-23
  • 1 回答
  • 0 关注
  • 165 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号