1

介绍

我正在尝试MudTextField<T>mudblazor库扩展 的功能。通常我会创建一个包装器,但由于我要更改的行为仅在受保护的方法中可用,所以我选择继承MudTextField<T>Component。目标是创建一个克隆,仅在我通过覆盖某些方法更改的功能上有所不同。

继承的组件

所以我创建了一个CustomMudTextField<T>组件。

CustomMudTextField.razor

@using System.Runtime.CompilerServices
@using Microsoft.AspNetCore.Components.Rendering
@using Microsoft.AspNetCore.Components.RenderTree
@inherits MudTextField<T>
@typeparam T

@code
{
    // omitted custom logic
}

问题在于,基本 Control 不再被渲染。所以我尝试手动渲染基类。我从docs中获得灵感。

CustomMudTextField.razor

@using System.Runtime.CompilerServices
@using Microsoft.AspNetCore.Components.Rendering
@using Microsoft.AspNetCore.Components.RenderTree
@inherits MudTextField<T>
@typeparam T

@CustomRender

@code
{
    private RenderFragment CustomRender { get; set; }
    private RenderFragment RenderBase() => builder =>
    {
        base.BuildRenderTree(builder);
    };

    protected override void OnInitialized()
    {
        base.OnInitialized();
        CustomRender = RenderBase();
    }

    // omitted custom logic
}

我希望它可以像基本组件一样工作。现在父级的 UI 确实被渲染了,但基本功能根本不起作用。

我也尝试过这个 github issue中讨论的方法,但是下面的代码片段甚至不再编译了。

@inherits BaseComponent
@{ 
    base.BuildRenderTree(__builder);
}

那么如何渲染基本控件的内容呢?

其他 UI 框架使用可用于呈现基本控件的组件。我希望这在某种程度上类似于 blazors @ChildContent mechanic,即使它是一个完全不同的概念。有没有办法继承和渲染MudTextField<T>,使其行为完全相同?我错过了什么?

4

2 回答 2

2

如果您不更改渲染片段。您可以简单地创建一个新类.cs并继承该组件。由于它不使用.razor它不会覆盖渲染片段。例如:

ComponentA.razor

<h1>@Name</h1>
<button @onclick="DoSomething">Do Something</button>
@x
@code {
    protected  int x = 0;
    public virtual string Name {get;set;} = "ComponentA";
    public virtual void DoSomething()
    {
        x = x + 1;    
    }
}

ComponentB.cs

    public class SomeComponentB : SomeComponentA
    {
        override public string Name {get;set;} = "ComponentB";
        
        override  public void DoSomething()
        {
            x = x + 2;    
        }
    }

ComponentB 仍然继承ComponentBase,可以作为组件使用。

<ComponentB />

这是一个有效的REPL

更新:

注意:如果要在派生类中添加内容,可以重写 BuildRenderTree 方法,如下所示:

 public class SomeComponentB : SomeComponentA
 {
      private string message = "A message from derived component";
      override public string Name {get;set;} = "ComponentB";
        
      override  public void DoSomething()
      {
            x = x + 2;    
      }
    

      protected override void BuildRenderTree(RenderTreeBuilder __builder)
      {
           
          __builder.OpenElement(0, "div");
          __builder.AddContent(1, message);
          __builder.CloseElement();

          base.BuildRenderTree(__builder);
      }
 }
于 2021-09-28T11:59:05.213 回答
1

你的问题是那MudTextField不是设计成的inherited。它的标记被定义为 Razor,因此您添加到继承组件的任何标记都会覆盖父组件中的内容。因此,您必须在继承的组件中复制标记。有时您很幸运,但大多数情况下您遇到了private字段/属性和/或其他类/字段/属性限制,因此您无法从子组件访问它们。

的标记MudTextField如下所示:

<CascadingValue Name="Standalone" Value="@Standalone" IsFixed="true">
    <MudInputControl Label="@Label" Variant="@Variant" HelperText="@HelperText" HelperTextOnFocus="@HelperTextOnFocus" CounterText="@GetCounterText()" FullWidth="@FullWidth" Class="@Classname" Error="@HasErrors" ErrorText="@GetErrorText()" Disabled="@Disabled" Margin="@Margin" Required="@Required">
        <InputContent>
            <MudInput T="string" @ref="_elementReference" @attributes="UserAttributes" InputType="@InputType" Lines="@Lines" Style="@Style" Variant="@Variant" TextUpdateSuppression="@TextUpdateSuppression" Value="@Text" 
                      ValueChanged="(s) => SetTextAsync(s)" Placeholder="@Placeholder" Disabled=@Disabled DisableUnderLine="@DisableUnderLine" ReadOnly="@ReadOnly" MaxLength="@MaxLength"
                      Adornment="@Adornment" AdornmentText="@AdornmentText" AdornmentIcon="@AdornmentIcon" AdornmentColor="@AdornmentColor" IconSize="@IconSize" OnAdornmentClick="@OnAdornmentClick" Error="@Error" 
                      Immediate="@Immediate" Margin="@Margin" OnBlur="@OnBlurred" OnKeyDown="@InvokeKeyDown" OnInternalInputChanged="OnChange" OnKeyPress="@InvokeKeyPress" OnKeyUp="@InvokeKeyUp"
                      KeyDownPreventDefault="KeyDownPreventDefault" KeyPressPreventDefault="KeyPressPreventDefault" KeyUpPreventDefault="KeyUpPreventDefault"
                      HideSpinButtons="true" Clearable="@Clearable" OnClearButtonClick="@OnClearButtonClick" />
        </InputContent>
    </MudInputControl>
</CascadingValue>

我还没有完全通过它,但我立即可以看到@ref="_elementReference"哪里_elementReference是私人的。

于 2021-09-28T15:23:39.113 回答