如何将一个对象属性作为参数传递给 Razor 组件

3
我有一个剃刀组件库,其中我正在创建自定义的可重用组件。我有一个“ContentItem”组件,希望能够简单地绑定组件中对象的属性,然后使用反射或其他方法来发现必要的信息。例如:

ContentItem.razor
<div>
    <div>@DisplayName</div>
    <div>@PropertyValue</div>
</div>

ContentItem.razor.cs

public partial class ContentItem
{
        /// <summary>
        /// The property that this component will bind to
        /// </summary>
        [Parameter]
        public **???** ObjectProperty{ get; set; }
 
        public string DisplayName;
        public string PropertyValue;
 
        protected override void OnParametersSet()
        {
          try
          {
            DisplayName = //reflection or some way to get the display attribute from the Object Property
            PropertyValue = //reflection or inspection of the ObjectProperty

            base.OnParametersSet();
          }
         catch (Exception ex)
         {
            throw new exception("Error", ex);
         }
       } 

客户端应用程序页面

<div>
    <ContentItem ObjectProperty="@User.FirstName" />
</div>  

实际上,当你使用 "ContentItem" 组件时,你只需要传递 ObjectProperty,然后 "ContentItem" 组件将执行某种反射和/或检查该参数以按预期渲染 HTML 的操作。

2个回答

3
您需要将类、属性和值的类型分别传递给组件。
类型将是typeof(User),属性名称可以从nameof(User.FirstName)中派生,值将是User.FirstName值作为string或其他形式的内容。
您的ContentItem组件的参数将如下所示:
[Parameter]
public Type ObjectType { get; set; }

[Parameter]
public string ObjectProperty { get; set; }

[Parameter]
public string ObjectValue { get; set; }

代码可以这样调用:

<ContentItem 
            ObjectType="@(typeof(User))" 
            ObjectProperty="@(nameof(User.FirstName))" 
            ObjectValue="@User.FirstName" />

假设您的类是这样的:

public class User
{
    [DisplayName("First name")]
    public string FirstName { get; set; }
}

在组件中使用下面的辅助方法获取DisplayName

public static string GetDisplayName(Type @type, string propertyName)
{
    var memberInfo = @type?.GetMember(propertyName)[0];

    var displayNameAttribute = memberInfo?.GetCustomAttribute<DisplayNameAttribute>();
    string displayName = displayNameAttribute?.DisplayName ?? "";

    return string.IsNullOrEmpty(displayName) ? propertyName : displayName;
}

2
我用层叠值/参数解决了这个问题。我有一个容器组件,它公开了一个名为“BindObject”的层叠值。
<CascadingValue Name="BindObject" Value="@BindObject">
@if (BindObject != null)
{
    @ChildContent
}
else
{
    if (PlaceholderLines > 0)
    {
        <Placeholder DisplayLines="@PlaceholderLines"></Placeholder>
    }
}
</CascadingValue>

然后在我的内容项组件中,我使用级联参数来获取对象。我还公开了一个“BindProperty”参数。

    /// <summary>
    /// When the ContentItem is placed inside of a ContentItems
    /// container then the BindObject will be passed as a Cascading
    /// Parameter.  This ContentItem will then use reflection to
    /// populate the Label and Value of this control.
    /// </summary>
    [CascadingParameter(Name = "BindObject")]
    public object BindObject { get; set; }

    /// <summary>
    /// If a BindProperty is specified then a generic placeholder
    /// will be used while the property is being loaded or evaluated.
    /// The BindProperty only works when the ContentItem is placed
    /// inside of a ContentItems control.
    /// </summary>
    [Parameter]
    public string BindProperty { get; set; }

现在我可以在内容项容器组件中一次指定绑定对象,然后在其中放置单个内容项组件。我指定“BindProperty”,然后在模型上使用反射。

        <ContentItems @ref="requestItems" BindObject="@jsonObject">
            <ContentItem BindProperty="@nameof(jsonObject.UserId)" />
            <ContentItem BindProperty="@nameof(jsonObject.FirstName)" />
            <ContentItem BindProperty="@nameof(jsonObject.LastName)" />
            <ContentItem BindProperty="@nameof(jsonObject.Email)" />
            <ContentItem BindProperty="@nameof(jsonObject.RegionId)" />
            <ContentItem BindProperty="@nameof(jsonObject.Password)" />
            <ContentItem BindProperty="@nameof(jsonObject.Id)" />
        </ContentItems>

我使用数据注解来指定显示名称、要求、图标等。内容项组件使用反射来消耗这些信息,因此它只需要在模型本身中定义。我还编写了一些自定义验证注解来保持一致性。

    [Required]
    [DisplayName("First Name:")]
    [KzAlphaOnly(ErrorMessage = "Only letters are allowed here.")]
    [MaxLength(16, ErrorMessage = "First name must be 16 characters or less.")]
    [KzIcon(FaIcon = FaIcons.User)]
    public string FirstName { get; set; }

    [Required]
    [KzAlphaOnly(ErrorMessage = "Only letters are allowed here.")]
    [MaxLength(64, ErrorMessage = "Last Name name must be 64 characters or less.")]
    [KzIcon(FaIcon = FaIcons.User)]
    [DisplayName("Last Name:")]
    public string LastName { get; set; }

    [Required]
    [StringLength(256)]
    [DisplayName("Email:")]
    [KzEmail]
    [KzIcon(FaIcon = FaIcons.EnvelopeSquare)]
    public string Email { get; set; }

现在我可以轻松地显示模型中的信息,这对于模板、操作卡等非常有用。 输入图像描述

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接