【问题标题】:How in Blazor Set component properties through a Reference that obtained by @RefBlazor中如何通过@Ref获取的Reference设置组件属性
【发布时间】:2021-06-14 15:47:11
【问题描述】:

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

<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 而大多数引用的属性都无法设置?或者有没有办法让这个工作?

【问题讨论】:

  • 我将对象转换为 Button,然后使用它的属性。
  • 我发布了两段代码,一段用于标记,另一段用于后面的代码,我发布的第二个代码块是后面的代码。

标签: c# asp.net-core blazor blazor-server-side


【解决方案1】:

我不是 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,也不知道如何或何时使用它。

【讨论】:

  • 我的目标是消除在页面上定义多个属性并在标签中分配它们的需要,因为当属性和/或控件的数量很多时,这会变得很多工作。跨度>
【解决方案2】:

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

如果您需要从代码中设置某些内容,您可以公开一个公共方法,例如SetText 在组件类上,它会为您执行此操作。

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

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

我不是在推广这种方法,我更喜欢在@Pidon 的回答中使用这种方法。 此外,您可以考虑 - 也许您有太多参数,应该考虑使用 Options 参数来合并

【讨论】:

    【解决方案3】:
    <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组件被实例化的组件。请注意,您应该将父组件的上述属性设置为属性属性......您不能在组件实例化之外设置它们。现在这是一个警告,但史蒂夫安德森已经很难过它很快就会成为编译器错误。这是在父组件中实例化组件的方式:

    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 组件中引发点击事件,并且按钮组件应该将此事件传播给父组件;也就是在父组件上执行 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 方法,当被调用时,显示对话框小部件。这很好且合法,但切勿尝试在组件实例化之外更改或设置参数属性。

    【讨论】:

    • 我想看看是否有办法在后面的代码中使用控件引用并使用它们的所有成员,但是正如您所讨论的,只能从引用中调用控件(组件)方法,有一些框架同时允许 MVVM 和基于 Reference 的编程,但 Blazor 似乎不是其中之一。
    猜你喜欢
    • 2017-05-01
    • 2021-12-11
    • 2021-12-31
    • 1970-01-01
    • 2023-03-17
    • 2022-10-13
    • 1970-01-01
    • 2021-05-27
    • 2020-05-14
    相关资源
    最近更新 更多