如何在 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
方法,当被调用时,显示对话框小部件。这很好而且合法,但永远不要尝试在组件实例化之外更改或设置参数属性。
我有一个组件,我在页面变量中设置了它的引用:
<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
方法,当被调用时,显示对话框小部件。这很好而且合法,但永远不要尝试在组件实例化之外更改或设置参数属性。