C# Blazor Can';更新用户界面

C# Blazor Can';更新用户界面,c#,blazor,C#,Blazor,我看过很多关于Blazor中UI更新问题的帖子,但是我以前读过的方法都不管用。我试图复制我在JavaScript中看到的一些密码策略验证器。然而,我正试图用C#和Blazor一起做这件事。如果我在调试模式下一步一步地完成代码,它工作得很好,但是如果要上线,即使使用StateHasChanged请求,我也无法更新UI,如下所示: 代码: private bool pwSpecialChar{get;set;} 私有布尔值{get;set;} 私有布尔pwLower{get;set;} 私有布尔pw

我看过很多关于Blazor中UI更新问题的帖子,但是我以前读过的方法都不管用。我试图复制我在JavaScript中看到的一些密码策略验证器。然而,我正试图用C#和Blazor一起做这件事。如果我在调试模式下一步一步地完成代码,它工作得很好,但是如果要上线,即使使用StateHasChanged请求,我也无法更新UI,如下所示: 代码:

private bool pwSpecialChar{get;set;}
私有布尔值{get;set;}
私有布尔pwLower{get;set;}
私有布尔pwDigit{get;set;}
私有bool pwLength{get;set;}
专用异步任务ValidatePassword(KeyboardEventArgs args args)
{
字符串pw=args.Key;
如果(!string.IsNullOrEmpty(Model.Password))
{
如果(Model.Password.Length<8){pwLength=false;}否则{pwLength=true;}
if(Model.Password.Any(c=>char.IsSymbol(c))==false){pwSpecialChar=false;}else{pwSpecialChar=true;}
if(Model.Password.Any(c=>char.IsDigit(c))==false{pwDigit=false;}else{pwDigit=true;}
if((Model.Password.Where(char.IsUpper.Count()>=1)==false){pwUpper=false;}else{pwUpper=true;}
if((Model.Password.Where(char.IsLower.Count()>=1)==false){pwLower=false;}else{pwLower=true;}
}
其他的
{
pwLower=false;
pwUpper=假;
pwDigit=false;
pwSpecialChar=假;
pwLength=假;
}
等待任务。延迟(500);
等待InvokeAsync(()=>StateHasChanged());
}
标记:

<div class="card-body">
    <h5>You must change your password before you can proceed.</h5>
    <ol>
    @if (pwLength == false)
    {
        <li style="color:red; font-weight:bold;"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-x-circle"><circle cx="12" cy="12" r="10"></circle><line x1="15" y1="9" x2="9" y2="15"></line><line x1="9" y1="9" x2="15" y2="15"></line></svg> &nbsp; Must Be at Least 8 Characters in Length</li>
    }
    else
    {
        <li style="color:green; font-weight:bold;"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-check-circle"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path><polyline points="22 4 12 14.01 9 11.01"></polyline></svg> &nbsp; Must Be at Least 8 Characters in Length</li>
    }
    @if (pwSpecialChar == false)
    {
        <li style="color:red; font-weight:bold;"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-x-circle"><circle cx="12" cy="12" r="10"></circle><line x1="15" y1="9" x2="9" y2="15"></line><line x1="9" y1="9" x2="15" y2="15"></line></svg> &nbsp; Pasword Must Contain at Least One Special Character</li>
    }
    else
    {
        <li style="color:green; font-weight:bold;"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-check-circle"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path><polyline points="22 4 12 14.01 9 11.01"></polyline></svg> &nbsp; Pasword Must Contain at Least One Special Character</li>
    }
    @if (pwDigit == false)
    {
        <li style="color:red; font-weight:bold;"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-x-circle"><circle cx="12" cy="12" r="10"></circle><line x1="15" y1="9" x2="9" y2="15"></line><line x1="9" y1="9" x2="15" y2="15"></line></svg> &nbsp; Pasword Must Contain at Least One Number</li>
    }
    else
    {
        <li style="color:green; font-weight:bold;"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-check-circle"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path><polyline points="22 4 12 14.01 9 11.01"></polyline></svg> &nbsp; Pasword Must Contain at Least One Number</li>
    }
    @if (pwUpper == false)
    {
        <li style="color:red; font-weight:bold;"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-x-circle"><circle cx="12" cy="12" r="10"></circle><line x1="15" y1="9" x2="9" y2="15"></line><line x1="9" y1="9" x2="15" y2="15"></line></svg> &nbsp; Pasword Must Contain at Least One Upper Case Letter</li>
    }
    else
    {
        <li style="color:green; font-weight:bold;"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-check-circle"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path><polyline points="22 4 12 14.01 9 11.01"></polyline></svg> &nbsp; Pasword Must Contain at Least One Upper Case Letter</li>
    }
    @if (pwLower == false)
    {
        <li style="color:red; font-weight:bold;"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-x-circle"><circle cx="12" cy="12" r="10"></circle><line x1="15" y1="9" x2="9" y2="15"></line><line x1="9" y1="9" x2="15" y2="15"></line></svg> &nbsp; Pasword Must Contain at Least One Lower Case Letter</li>
    }
    else
    {
        <li style="color:green; font-weight:bold;"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-check-circle"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path><polyline points="22 4 12 14.01 9 11.01"></polyline></svg> &nbsp; Pasword Must Contain at Least One Lower Case Letter</li>
    }
    </ol>
    <EditForm Model="Model" OnValidSubmit="ChangePassword" OnInvalidSubmit="ChangePasswordError" id="validateForm">
        <DataAnnotationsValidator />
            <div class="col-md-12">
                <div class="form-group">
                     <div>
                        <label>New Password *</label>
                            <SfTextBox @bind-Value="@Model.Password" Placeholder="New Password *" Type="InputType.Password" OnKeyDown="ValidatePassword" required></SfTextBox>
                            <ValidationMessage For="@(() => Model.Password)" />
                     </div>
                </div>
                <div class="form-group">
                <div>
                    <label>Confirm New Password *</label>
                    <SfTextBox @bind-Value="@Model.ConfirmPassword" Placeholder="Confirm New Password *" Type="InputType.Password" required></SfTextBox>
                    <ValidationMessage For="@(() => Model.ConfirmPassword)" />
                </div>
            </div>
        </div>
    <button type="submit" class="btn btn-primary">Change Password</button>
    </EditForm>
</div>

您必须更改密码才能继续。
@if(pwLength==false)
{
长度必须至少为8个字符
}
其他的
{
长度必须至少为8个字符
}
@如果(pwSpecialChar==false)
{
Pasword必须至少包含一个特殊字符
}
其他的
{
Pasword必须至少包含一个特殊字符
}
@如果(pwDigit==false)
{
Pasword必须至少包含一个数字
}
其他的
{
Pasword必须至少包含一个数字
}
@如果(pwUpper==false)
{
Pasword必须至少包含一个大写字母
}
其他的
{
Pasword必须至少包含一个大写字母
}
@如果(pwLower==false)
{
Pasword必须至少包含一个小写字母
}
其他的
{
Pasword必须至少包含一个小写字母
}
新密码*
确认新密码*
修改密码

可能是因为您没有正确地等待ValidatePassword函数。(不确定,只是我认为正在发生的事情)。当特别调用任务时,您需要等待它。像这样:

OnKeyDown="@( async (e) => await ValidatePassword(e))"
然后在另一个线程中调用
statehaschange()
函数,从原始线程中删除了两个未被等待的线程。以下是我如何处理需要等待的异步函数:

用户界面:

在这种情况下,它是一个
void
而不是
任务
,因此UI将等待它,但由于它是一个
异步void
,您仍然可以等待它,我相信它将在同一线程中执行。因此,您可以将
statehaschange()
作为同步函数调用



另外,正如@DekuDeku所提到的,如果您真的关心按下了哪个按钮,您可能只需要使用
@onkeypress

可能是您没有正确地等待ValidatePassword函数。(不确定,只是我认为正在发生的事情)。当特别调用任务时,您需要等待它。像这样:

OnKeyDown="@( async (e) => await ValidatePassword(e))"
然后在另一个线程中调用
statehaschange()
函数,从原始线程中删除了两个未被等待的线程。以下是我如何处理需要等待的异步函数:

用户界面:

在这种情况下,它是一个
void
而不是
任务
,因此UI将等待它,但由于它是一个
异步void
,您仍然可以等待它,我相信它将在同一线程中执行。因此,您可以将
statehaschange()
作为同步函数调用



另外,正如@DekuDeku所提到的,如果您真正关心按下了哪个按钮,您可能只需要使用
@onkeypress

您的问题在于事件的顺序。按键事件发生,因此在每次按键时运行
ValidatePassword
,但是
InputText
,几乎可以肯定的是
SFTextBox
,只有在输入失去焦点时才更新模型值。无法更改
InputText
上的此行为,可能还有
SFTextBox

下面的独立演示页面显示了如何使用控件上的
oninput
事件解决问题,并使用
ChangeEventArgs
直接捕获输入的文本

@page "/password"
<h3>PasswordTest</h3>

<EditForm EditContext="this.editContext">
    <InputText type="password" @bind-Value="model.Password" @oninput="CheckPassword"></InputText>
</EditForm>
<div>@enteredPassword</div>
<div>@errorMessage</div>
@code {

    private Model model { get; set; } = new Model();

    private string enteredPassword = string.Empty;
    private string errorMessage = "Too short! Keep Typing...";

    private EditContext editContext;

    protected override Task OnInitializedAsync()
    {
        this.editContext = new EditContext(model);
        return Task.CompletedTask;
    }

    private void CheckPassword(ChangeEventArgs e)
    {
        this.enteredPassword = e.Value.ToString();
        if (this.enteredPassword.Length > 7)
            errorMessage = "Good to Go.";
        else
            errorMessage = $"Too short by {this.enteredPassword.Length - 8}! Keep Typing...";
        StateHasChanged();
    }

    public class Model
    {
        public string Password { get; set; }
    }
}
@page”/password
密码测试
@输入密码
@错误信息
@代码{
私有模型模型{get;set;}=new Model();
输入的私有字符串password=string.Empty;
脉波重复间隔
OnKeyDown="@( async (e) => await ValidatePassword(e))"
<Button @onclick="ValidatePassword" />
<input type="submit" @onclick="ValidatePassword" />
async void ValidatePassword()
{
   ...
   await Task.Delay(500);
   StateHasChanged();
}
@page "/password"
<h3>PasswordTest</h3>

<EditForm EditContext="this.editContext">
    <InputText type="password" @bind-Value="model.Password" @oninput="CheckPassword"></InputText>
</EditForm>
<div>@enteredPassword</div>
<div>@errorMessage</div>
@code {

    private Model model { get; set; } = new Model();

    private string enteredPassword = string.Empty;
    private string errorMessage = "Too short! Keep Typing...";

    private EditContext editContext;

    protected override Task OnInitializedAsync()
    {
        this.editContext = new EditContext(model);
        return Task.CompletedTask;
    }

    private void CheckPassword(ChangeEventArgs e)
    {
        this.enteredPassword = e.Value.ToString();
        if (this.enteredPassword.Length > 7)
            errorMessage = "Good to Go.";
        else
            errorMessage = $"Too short by {this.enteredPassword.Length - 8}! Keep Typing...";
        StateHasChanged();
    }

    public class Model
    {
        public string Password { get; set; }
    }
}