【问题标题】:Blazor Can't Update UIBlazor 无法更新用户界面
【发布时间】:2021-06-04 23:45:07
【问题描述】:

我看过很多关于更新 Blazor 中的 UI 问题的帖子,但我之前阅读的方法都没有奏效。我正在尝试复制我在 JavaScript 中看到的一些密码策略验证器。但是,我正在尝试使用 Blazor 在 C# 中执行此操作。如果我在调试模式下单步执行代码,它可以完美运行,但即使使用 StateHasChanged 请求,我也无法更新 UI,如下所示: 代码:

private bool pwSpecialChar { get; set; }
private bool pwUpper { get; set; }
private bool pwLower { get; set; }
private bool pwDigit { get; set; }
private bool pwLength { get; set; }

private async Task ValidatePassword(KeyboardEventArgs args)
{
    string pw = args.Key;
    if (!string.IsNullOrEmpty(Model.Password))
    {
        if (Model.Password.Length < 8) { pwLength = false; } else { 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; }
    }
    else
    {
        pwLower = false;
        pwUpper = false;
        pwDigit = false;
        pwSpecialChar = false;
        pwLength = false;
    }
    await Task.Delay(500);
    await 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>

【问题讨论】:

    标签: c# blazor


    【解决方案1】:

    您的问题在于事件的顺序。键事件发生并因此在每次按键时运行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; }
        }
    }
    

    【讨论】:

    • 正确。令人惊讶的是这个简单的任务是多么困难......或者至少我缺乏理解,但你做对了!我不得不明确引用 Microsoft.AspNetCore.Componets.ChangeEventArgs,因为 Syncfusion 有一个 Blazor.Navigations.ChangeEventArgs 但并不是每个人都在使用 Syncfusion 控件,所以在很多情况下他们不需要做类似的事情。
    • 没问题。我编写了自定义 InputBase 控件,因此深入研究了 Blazor 代码库。
    【解决方案2】:
    <SfTextBox @bind-Value="@Model.Password" 
        Placeholder="New Password *" 
        Type="InputType.Password" 
        OnKeyDown="ValidatePassword" 
        required></SfTextBox>
    

    OnKeyDown 事件可能未正确触发,请尝试改用 @onkeypress。

    <SfTextBox @bind-Value="@Model.Password" 
             Placeholder="New Password *" 
             Type="InputType.Password" 
             @onkeypress="ValidatePassword" 
             required></SfTextBox>
    

    【讨论】:

    • 感谢您的回复,也尝试了一下,并结合他们建议的第一个回复,但由于某种原因我无法更新?
    【解决方案3】:

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

    OnKeyDown="@( async (e) => await ValidatePassword(e))"
    

    然后在另一个线程中也调用了StateHasChanged() 函数,其中两个从原始线程中删除了未被等待的。以下是我如何处理需要等待的异步函数:

    用户界面:

    <Button @onclick="ValidatePassword" />
    <input type="submit" @onclick="ValidatePassword" />
    

    代码:

    async void ValidatePassword()
    {
       ...
       await Task.Delay(500);
       StateHasChanged();
    }
    

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


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

    【讨论】:

    • 感谢您的回复。你说的很有道理,我认为这肯定是解决办法……但令人惊讶地尝试了这两种方法,但都没有成功。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-02
    • 2014-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多