如何在 Blazor 中通过 @Ref 获得的引用设置组件属性

How in Blazor Set component properties through a Reference that obtained by @Ref

我有一个组件,我在页面变量中设置了它的引用:

<BlazorWebFormsComponents.Button OnClick="@((args) => btnForms_Clicked(formsButton, args))" @ref="formsButton" Text="Forms Button" CssClass="btn btn-primary">
    
</BlazorWebFormsComponents.Button>

在事件处理程序中我设置了一个按钮属性(文本):

Button formsButton;

public void btnForms_Clicked(object sender, MouseEventArgs e)
{                        
    if (sender is Button)
        (sender as Button).Text = "Good Bye";
}

对于大多数 Button 属性,此代码无效,对于 BackColor 有效,但对于 Text 无效。 Blazor 还制作了分配线,绿色下划线并表示“不应在其组件之外设置组件参数“zzz””,那么为什么 Blazor 提供 @Ref 而大多数引用的属性无法设置?或者有什么办法可以做到这一点?

我不是 Blazor 的出口商,但 运行 也参与其中。您可以通过绑定到页面上的 属性 来执行此操作。

<BlazorWebFormsComponents.Button OnClick="@((args) => btnForms_Clicked(formsButton, args))" @ref="formsButton" Text="@ButtonText" CssClass="btn btn-primary">

</BlazorWebFormsComponents.Button>

@code{
    private string ButtonText { get; set; } = "Forms button";

    public void btnForms_Clicked(object sender, MouseEventArgs e)
    {
        ButtonText = "Good bye";
    }
}

我从未使用过@Ref,也不知道如何或何时使用它。

警告是因为从代码设置 [Parameter] 属性会导致渲染树不同步,并导致组件的双重渲染。

如果您需要从代码中设置一些东西,您可以公开一个 public 方法,例如SetText 在组件 class 上,它会为您完成。

在内部,组件 [Parameter] 应该引用局部变量。

string _text;
[Parameter] 
public string Text { get => _text; set => SetText(value);}
public void SetText(string value)
{
  _text = value;
}

我不提倡这种做法,我更喜欢使用@Pidon 的回答中的做法。 此外,您可以考虑 - 也许您的参数太多,应该考虑一个 Options 参数来合并

<Button OnClick="@((args) => btnForms_Clicked(formsButton, args))" @ref="formsButton" Text="Forms Button" CssClass="btn btn-primary">

您的 Button 组件应定义如下:

@code
{
    [Parameter]
    public EventCallback<MouseEventArgs> OnClick {get; set;} 
    [Parameter]
    public string Text {get; set;} 

}

以上代码定义了两个应该从父组件分配的参数属性。父组件是实例化 Button 组件的组件。请注意,您应该将父组件的上述属性设置为属性属性......您不能在组件实例化之外设置它们。现在它是一个警告,但 Steve Anderson 已经很伤心它很快就会成为一个编译器错误。这是在父组件中实例化组件的方式:

Parent.razor

<Button OnClick="@((args) => btnForms_Clicked(args))" @ref="formsButton" 
      Text="_text" CssClass="btn btn-primary">
    
</Button>

@code
{
private Button formsButton;

// Define a local variable wich is bound to the Text parameter
private string _text = "Click me now...";

public void btnForms_Clicked( MouseEventArgs e)
{                        
    _text = "You're a good clicker.";
}
}

注意:当你点击Button组件时,Button组件应该触发一个click事件,按钮组件应该将这个事件传播给父组件;即在父组件上执行 btnForms_Clicked 方法,具体做法如下:

Button.razor

<div @onclick="InvokeOnClick">@Text</div>

@code
    {
        [Parameter]
        public EventCallback<MouseEventArgs> OnClick {get; set;} 
        [Parameter]
        public string Text {get; set;} 

        private async Task InvokeOnClick ()
        {
             await OnClick.InvokeAsync(); 
        }
    
    } 

请注意,为了演示如何在 Button 组件中引发事件并将其传播到父组件,我使用了 div 元素,但您可以使用按钮元素等.

@onclick 是一个编译器指令,指示创建一个 EventCallback 'delegate',其值为事件处理程序 InvokeOnClick。现在,无论何时单击 div 元素,都会引发 click 事件,并调用事件处理程序 InvokeOnClick...从该事件我们执行 EventCallback 'delegate' OnClick;也就是说,我们调用父组件中定义的btnForms_Clicked方法

那么 @ref 指令有什么用呢?您可以使用 @ref 指令获取对包含要从其父组件调用的方法的组件的引用:假设您定义了一个用作对话框小部件的子组件,并且该组件定义了一个 Show方法,当被调用时,显示对话框小部件。这很好而且合法,但永远不要尝试在组件实例化之外更改或设置参数属性。