简体   繁体   English

Blazor 7 中的 bind:after 和 bind:set 有什么区别?

[英]What is the difference between bind:after and bind:set in Blazor 7?

Recently, in Blazor 7, a feature has been added to make it easier to bind and call the method based on changes in the bound expression.最近在Blazor 7中,增加了一个功能,可以更方便地根据绑定表达式的变化来绑定和调用方法。

In .NET 7, you can now easily run async logic after a binding event has completed using the new @bind:after modifier:在 .NET 7 中,您现在可以使用新的 @bind:after 修饰符在绑定事件完成后轻松运行异步逻辑:

    <input @bind="searchText" @bind:after="PerformSearch" />
@code {
    string searchText = "";

    async Task PerformSearch()
    {
        // Do something async with searchText
    }
}

In this example, the PerformSearch async method runs automatically after any changes to the search text are detected.在此示例中,PerformSearch 异步方法在检测到对搜索文本的任何更改后自动运行。

Another method has been added too.还添加了另一种方法。 The @bind:get and @bind:set modifiers are always used together. @bind:get 和@bind:set 修饰符总是一起使用。 The @bind:get modifier specifies the value to bind to, and the @bind:set modifier specifies a callback that's called when the value changes. @bind:get 修饰符指定要绑定的值,@bind:set 修饰符指定值更改时调用的回调。

The questions are:问题是:

What is the difference between @bind:after="PerformSearch" and @bind:set="PerformSearch" ? @bind:after="PerformSearch"@bind:set="PerformSearch"有什么区别? Both of these seem to call the PerformSearch after the searchText is changed.searchText更改后,这两个似乎都调用了PerformSearch

Where is the use of each?每个的用途在哪里?

Why is it @bind:get+@bind:set and not just @bind+@bind:set ?为什么是@bind:get+@bind:set而不仅仅是@bind+@bind:set

  • Because if you see <input @bind="@val" @bind:set="@MyMethod" /> often, it creates confusion:因为如果你经常看到<input @bind="@val" @bind:set="@MyMethod" /> ,它会造成混淆:

  • It looks as if the @bind:set is what makes it a two-way binding, and that you could make it one-way by removing that.看起来好像@bind:set是使它成为双向绑定的原因,并且您可以通过删除它使其成为单向绑定。 Whereas in fact that would be wrong (you'd still have a two-way binding, just one that behaves differently now).而实际上那是错误的(您仍然有双向绑定,只是现在行为不同)。

  • It looks as if it would be equivalent to write <input value="@val" @bind:set="@MyMethod /> , and it almost is, but not quite because the formatting logic would differ. Much better not to create the ambiguity and have one correct solution.看起来它等同于编写<input value="@val" @bind:set="@MyMethod /> ,它几乎是,但不完全是因为格式化逻辑会有所不同。最好不要创建歧义,并有一个正确的解决方案。

  • We can avoid the above problems by having a compiler rule that @bind:get and @bind:set must always be used as a pair - you can't just have one of them and not the other (nor can you have them with @bind ).我们可以通过编译器规则避免上述问题, @bind:get@bind:set必须始终成对使用 - 你不能只使用其中一个而不使用另一个(也不能使用@bind )。 So none of the weird cases will arise.所以不会出现任何奇怪的情况。

Couldn't you use @bind:set to achieve (in effect) @bind:after , and hence we don't need @bind:after ?您不能使用@bind:set来实现(实际上) @bind:after ,因此我们不需要@bind:after吗?

  • Theoretically yes.理论上是的。 You could @bind:set to a method that writes to your field and then runs your async logic.您可以将@bind:set为写入您的字段然后运行您的异步逻辑的方法。 However, this is far less obvious for newcomers, and is less convenient in common cases.然而,这对于新手来说远没有那么明显,并且在常见情况下也不太方便。 And it invites mistakes: if you do something async before setting the field, the UI will temporarily revert and generally behave badly.它会引发错误:如果您在设置字段之前执行异步操作,UI 将暂时恢复并且通常表现不佳。 So it's valuable to have @bind:after for convenience and to guide correct usage.因此,为了方便和指导正确使用,@bind:after 很有价值。 We can regard @bind:get/@bind:set as a more advanced case mainly for people implementing bindable components, as it gives them a really clean and safe solution, and such developers are advanced enough to understand that they just shouldn't do async work before calling ValueChanged .我们可以将@bind:get/@bind:set视为更高级的案例,主要针对实现可绑定组件的人员,因为它为他们提供了一个真正干净和安全的解决方案,并且这些开发人员足够先进,明白他们不应该这样做在调用ValueChanged之前异步工作。

Can you use all three at once, eg, <input @bind:get="@value" @bind:set="@MyMethod" @bind:after="@DoStuff" /> ?你能同时使用这三个吗,例如<input @bind:get="@value" @bind:set="@MyMethod" @bind:after="@DoStuff" />

  • Sure, why not?当然,为什么不呢? I think that the generated logic should await MyMethod before calling DoStuff, since "after" feels like it means "after all the work involved in calling set".我认为生成的逻辑应该在调用 DoStuff 之前等待 MyMethod,因为“之后”感觉它意味着“在调用 set 所涉及的所有工作之后”。 It's an edge case but I can't think of any problems this will cause nor any major increase in implementation cost.这是一个边缘案例,但我想不出这会导致任何问题,也不会大幅增加实施成本。

Do other @bind modifiers like @bind:event and @bind:format work with this? @bind:event 和@bind:format等其他@bind修饰符是否适用于此?

  • Yes, and that's partly why it's a big improvement over manual value/onchange pairs.是的,这就是为什么它比手动value/onchange对有很大改进的部分原因。

you can refer this link get more idea https://github.com/do.net/as.netcore/issues/39837你可以参考这个链接得到更多的想法https://github.com/do.net/as.netcore/issues/39837

What is the difference between @bind:after="PerformSearch" and @bind:set="PerformSearch"? @bind:after="PerformSearch" 和@bind:set="PerformSearch" 有什么区别?

  1. You should only use @bind:after="PerformSearch" with @bind="searchText" ,in which case the bind will set the value of searchText , so you shouldn't also try and set it in PerformSearch .您应该只将@bind:after="PerformSearch"@bind="searchText" " 一起使用,在这种情况下,绑定将设置searchText的值,因此您也不应该尝试在PerformSearch中设置它。

  2. If you use @bind:set="PerformSearch" then you must set the value of searchText in PerformSearch , and use @bind:get="searchText" .如果您使用@bind:set="PerformSearch"那么您必须在PerformSearch中设置searchText的值,并使用@bind:get="searchText"

Where is the use of each?每个的用途在哪里?

The MS Docs article I think gives a good guide.我认为 MS Docs 文章提供了很好的指导。 It all depends on your knowledge level on components.这完全取决于您对组件的知识水平。

It's important to understand two points:理解两点很重要:

  1. This is Razor syntax, not C#.这是 Razor 语法,而不是 C#。
  2. It's just syntactic sugar: high level functionality, shorthand Razor directives to encapsulate existing functionality.它只是语法糖:高级功能,简写 Razor 指令来封装现有功能。

Also note:另请注意:

Here's my demo page for this answer.这是我的这个答案的演示页面。

@page "/"

<PageTitle>Index</PageTitle>

<input class="form-control mb-3" type="text" @bind:get="this.Value" @bind:set="ValueSetter" @bind:event="oninput" />
<input class="form-control mb-3" type="text" @bind:get="this.Value" @bind:after="ValueSetter" />
<input class="form-control mb-3" type="text" @bind="this.Value" @bind:after="DoSearch" @bind:event="oninput"/>

<div class="alert alert-info m-2 p-2">
    @Value
</div>

<div class="alert alert-primary m-2 p-2">
    @message
</div>

@code {
    private string? Value; 
    private string message = "Not Set";

    private async Task DoSearch()
    {
        await Task.Delay(1000);
        message= $"Set at {DateTime.Now.ToLongTimeString()}";
    }

    private void ValueSetter(string __value)
        => this.Value = __value;

    private Task SearchSetter(string __value)
    {
        this.searchText = __value;
        return DoSearch();
    }
}

Let's look at the actual C# code the Razor compiler builds.让我们看看 Razor 编译器构建的实际 C# 代码。

This is the code snippet when just using bind:set=this.ValueSetter :这是仅使用bind:set=this.ValueSetter时的代码片段:

__builder.AddAttribute(8, "oninput", EventCallback.Factory.CreateBinder(
    this, 
    CompilerServices.RuntimeHelpers.CreateInferredBindSetter(
        callback: this.ValueSetter, 
        value: this.Value
        ),
    this.Value));

This simply calls the setter delegate assigned to set.这只是调用分配给 set 的 setter 委托。

This is the code snippet when using :bind=this.Value and @bind:after=DoSearch :这是使用:bind=this.Value@bind:after=DoSearch DoSearch 时的代码片段:

__builder.AddAttribute(14, "oninput", EventCallback.Factory.CreateBinder(
    this, CompilerServices.RuntimeHelpers.CreateInferredBindSetter(
        callback: __value => { 
            this.Value = __value; 
            return RuntimeHelpers.InvokeAsynchronousDelegate(callback: DoSearch); 
        }, 
        value: this.Value), 
        this.Value));

It's a little more complicated.这有点复杂。 The compiler builds the equivalent to this:编译器构建等效于此:

Task AnonymousMethod(string __value)
{
    this.Value = __value;
    return DoSearch()
}

A Note on Development Environment Errors关于开发环境错误的说明

Depending on your development environment, you will get errors with certain combinations.根据您的开发环境,您会遇到某些组合的错误。 Some of which at the moment appear to be misleading or totally wrong.目前,其中一些似乎具有误导性或完全错误。 They will be fixed shortly.它们将很快得到修复。

Quote from Dan Roth: Hi folks.引用 Dan Roth 的话:大家好。 The VS fix for this just missed the window for 17.4.4 but should be addressed in the next VS patch update in February. VS 对此的修复只是错过了 17.4.4 的 window,但应该在 2 月份的下一个 VS 补丁更新中解决。 We apologize for the wait and thank you for your patience!对于让您久等了,我们深表歉意,感谢您的耐心等待!

In Visual Studio.在视觉工作室中。

This is a correct error:这是一个正确的错误:

<InputText class="form-control" @bind-Value:get="this.searchText" @bind-Value:set="this.SetSearchText" @bind-Value:after="DoSearch" />
Severity    Code    Description Project File    Line    Suppression State
Error (active)  RZ10019 Attribute 'bind-Value:after' can not be used with 'bind-Value:set'. Invoke the code in 'bind-Value:after' inside 'bind-Value:set' instead.

While this is bull!虽然这是牛!

<input class="form-control mb-3" type="text" @bind:get="this.Value" @bind:set="ValueSetter" @bind:event="oninput" />

And while it gives this error compiles and runs!虽然它给出了这个错误编译并运行!

Severity    Code    Description Project File    Line    Suppression State
Error (active)  CS1503  Argument 3: cannot convert from 'Microsoft.AspNetCore.Components.EventCallback<string>' to 'System.Action<string?>' 

And this line:这行:

<input class="form-control mb-3" type="text" @bind:get="this.Value" @bind:after="ValueSetter" />

Compiles but is obviously also total bull.编不过显然也是十足的牛逼。

__builder.AddMarkupContent(9, "\r\n\r\n<input class=\"form-control mb-3\" type=\"text\" @bind:get=\"this.Value\" @bind:after=\"ValueSetter\">\r\n\r\n");

在此处输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM