StateHasChanged()两次重新渲染一次组件 - c#

我正在制作一个Blazor服务器端项目,我想创建一个单击后即可停用的按钮,但不使用disabled<button>属性。代码很简单:

@functions {

    LogInForm logInForm = new LogInForm();
    bool IsDisabled;
    SignInResult result;

    protected override void OnInitialized()
    {
        IsDisabled = false;
    }

    async Task TryLogIn()
    {
        IsDisabled = true;
        StateHasChanged();
        result =  await _LogInService.TryLogIn(logInForm);
        Console.WriteLine("Logging status : " + (result.Succeeded ? "Sucess" : "Failure"));
        IsDisabled = false;
        StateHasChanged();
    }

}

出于奇怪的原因,第一个StateHasChanged不会触发,但是第二个会重新渲染页面。通过进入Debug模式并进入StateHasChanged()方法,可以很容易地进行测试。在第二次调用时,它确实在进入方法后停止在HTML代码上,但不是第一次。

为什么这样 ?

注意:我不是在寻找仅使用Task.DelayTask.Run(...)的解决方法,因为它们存在于这些线程和UI刷新线程之间的竞争状态,因此它不是可靠的解决方案。我正在通过使用诸如StateHasChanged()PropertyChanged之类的事件并将按钮作为子组件来寻找有关EventCallback行为或解决方法的答案。

编辑:经过一些测试,似乎StateHasChanged()仅在await上执行Task操作后才触发组件的重新渲染。可以通过在result = await _LogInService.TryLogIn(logInForm);行中添加注释或将IsDisabled = ...更改为await new Task.Run(() => { IsDisabled = ...})来轻松对其进行测试。我现在有一些解决方法,但是我仍然想知道为什么这是一个功能。 StateHasChanged()是否应在执行任何操作后重新渲染?还是认为只有async操作(因此大部分是服务器调用)才能更改UI中的某些内容?

参考方案

以下是描述重新渲染如何发生的执行流程:

父组件调用StateHasChanged
产生了一个新的渲染树
老树和新树之间的差异正在发生
传递给您的子组件的值被认为与其当前持有的值不同。
在子组件上调用SetParameters,以使用父级传递给它的值更新它们。

现在,在将值分配给局部变量IsDisabled之后调用StateHasChanged时,并不会真正更改组件的状态,因此没有理由调用StateHasChanged会产生重新渲染。当您调用StateHasChanged时,它只是将该组件的渲染请求排队。但是没有理由重新渲染...

或者它认为只有异步操作(因此大部分是服务器调用)才能
更改UI中的某些内容?

除了OnInitializedAsync方法外,操作的类型是否异步都无关紧要,在这种情况下,当OnInitializedAsync方法完成以再次使用新数据重新渲染UI时,将自动调用StateHasChanged方法。由异步调用检索的结果在OnInitializedAsync方法中执行。

更新:

您想要的东西可以通过多种方式完成,其中最简单的方法如下所示:

   <input type="button" value="Click me now"  disabled="@IsDisabled" @onclick="TryLogIn" />


@code{ 

    bool IsDisabled;

    protected override void OnInitialized()
    {
        IsDisabled = false;
    }

    async Task TryLogIn()
    {
        IsDisabled = true;

        // Do some async work here...
        // Note: Replace your async method with Task.Delay 
        await Task.Delay(5000);

        IsDisabled = false;

    }

}

这应该工作...
注意:禁用按钮控件的唯一方法是使用disabled属性

无需调用StateHasChanged方法。当编译器为您的组件创建EventCallback“委托”时,编译器插入您的源代码中的代码会自动调用它。

触发UI事件后,将自动调用StateHasChanged方法。

当回复有时是一个对象有时是一个数组时,如何在使用改造时解析JSON回复? - java

我正在使用Retrofit来获取JSON答复。这是我实施的一部分-@GET("/api/report/list") Observable<Bills> listBill(@Query("employee_id") String employeeID); 而条例草案类是-public static class…

改造正在返回一个空的响应主体 - java

我正在尝试使用Retrofit和Gson解析一些JSON。但是,我得到的响应机构是空的。当我尝试从对象中打印信息时,出现NullPointerException。我确保URL正确,并且我也确保POJO也正确。我正在使用jsonschema2pojo来帮助创建POJO类。这是我要解析的JSON{ "?xml": { "@versi…

每个文件合并后添加换行 - python

我有很多类似以下内容的JSON文件:例如。1.json{"name": "one", "description": "testDescription...", "comment": ""} test.json{"name"…

Json到php,json_decode返回NULL - php

我正在用PHP进行JSON解析器的一些API,用于存储有关遗产的信息。我在解析时遇到问题,因为它返回的是NULL值而不是数组或对象。简单的JSON代码可以很好地解析,但是可以这样:{"success":true,"totalCount":1,"data":[{"id":99694…

将ajax的值存储到javascript变量中 - javascript

我有一个php文件,其中我从服务器获取数据。该php文件的输出是一个包含json格式数据的变量。PHP文件:<?php $dbHostName = "localhost"; $dbUserName = "venseld"; $dbUserPass = "wecuuu"; $dbName = &…