【问题标题】:How Can I Pass an Object Property to a Razor Component as a Parameter如何将对象属性作为参数传递给 Razor 组件
【发布时间】:2021-03-30 07:42:17
【问题描述】:

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

ContentItem.razor

    <div>
      <div>@DisplayName</div>
      <div>@PropertyValue</div>
    </div>

ContentItem.razor.cs

public partial class ContentItem
{
        #region PARAMETERS
        /// <summary>
        /// The property that this component will bind to
        /// </summary>
        [Parameter]
        public **???** ObjectProperty{ get; set; }
        #endregion

        #region PROTECTED
        public string DisplayName;
        public string PropertyValue;
        #endregion 

        #region OVERRIDES
        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);
         }
       } 
       #endregion

客户端应用中的页面

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

所以基本上你在使用“ContentItem”组件时所要做的就是传递 ObjectProperty,然后“ContentItem”组件会对该参数执行某种反射和/或检查,以根据需要呈现 HTML .

【问题讨论】:

    标签: c# .net-core blazor razor-component-library


    【解决方案1】:

    您需要将类的类型、属性和值分别传递给组件。

    类型将为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; }
      

      现在我可以在 Content Items 容器组件中指定一次绑定对象,然后将各个 Content Item 组件放入其中。我指定“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; }
      

      现在我可以毫不费力地显示来自模型的信息。这对于模板、操作卡等很有用。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-11-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-01-25
        • 2019-03-11
        • 1970-01-01
        相关资源
        最近更新 更多