Set/Change Controller/ViewComponent 中 属性 的显示(Name="")属性
Set/Change Display(Name="") Attribute of a Property in Controller/ViewComponent
根据 2010 年的 this 回答,关于 mvc-2,这是不可能的。现在,在 asp.net-core 2.2 中呢?
我的用例:
我有一个 BaseViewModel
被 2 个视图使用:TableView
(对于用户)和 TableManagentView
(对于管理员)。 BaseViewModel
由 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/ViewData
或 TempData
,但这个解决方案对我没有吸引力。这样做的利弊是什么?
扩展我留下的评论,解决此问题的一种方法是让您的 BaseViewModel
成为抽象的 class 并从中派生出具体的 classes。所以 UserViewModel
和 AdminViewModel
。这两个具体的 classes 将成为 TableView
和 TableManagentView
的模型,并负责告诉 "outside world" 如何标记字段。
基础 class 有两个主要方面(除了你的普通字段):一个包含标签的抽象 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;
}
}
然后创建两个派生 classes 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>
并为基础 class 的每个字段设置适当的文本。
接下来,将您的 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 class(现在更简单了)
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
时,您会将 UserViewModel
传递给 BaseViewComponent
,它会计算出正确的标签。引入新字段现在需要您更改视图模型,向字典添加新条目。
它并不完美,但我认为这是解决问题的好方法。到目前为止,我不是 MVC 专家,所以也许其他人也可以想出一种更自然的方法来做到这一点。我还准备了一个工作示例应用程序并推送到 GitHub。您可以在这里查看:aspnet-view-component-demo。希望能有所帮助。
根据 2010 年的 this 回答,关于 mvc-2,这是不可能的。现在,在 asp.net-core 2.2 中呢?
我的用例:
我有一个 BaseViewModel
被 2 个视图使用:TableView
(对于用户)和 TableManagentView
(对于管理员)。 BaseViewModel
由 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/ViewData
或 TempData
,但这个解决方案对我没有吸引力。这样做的利弊是什么?
扩展我留下的评论,解决此问题的一种方法是让您的 BaseViewModel
成为抽象的 class 并从中派生出具体的 classes。所以 UserViewModel
和 AdminViewModel
。这两个具体的 classes 将成为 TableView
和 TableManagentView
的模型,并负责告诉 "outside world" 如何标记字段。
基础 class 有两个主要方面(除了你的普通字段):一个包含标签的抽象 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;
}
}
然后创建两个派生 classes 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>
并为基础 class 的每个字段设置适当的文本。
接下来,将您的 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 class(现在更简单了)
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
时,您会将 UserViewModel
传递给 BaseViewComponent
,它会计算出正确的标签。引入新字段现在需要您更改视图模型,向字典添加新条目。
它并不完美,但我认为这是解决问题的好方法。到目前为止,我不是 MVC 专家,所以也许其他人也可以想出一种更自然的方法来做到这一点。我还准备了一个工作示例应用程序并推送到 GitHub。您可以在这里查看:aspnet-view-component-demo。希望能有所帮助。