我已经按照下面的教程如何在 Blazor Webbassembly 中创建一个简单的向导组件,到目前为止一切都很好。
https://sinclairinat0r.com/2019/12/08/creating-a-simple-wizard-component-in-blazor
但是,当我尝试将向导放入如下所示的编辑表单中时,我遇到了问题。
@page "/wizarddemo"
<EditForm Model="@wizardViewModel" OnValidSubmit="@OnValidSubmit" OnInvalidSubmit="@OnInvalidSubmit">
<DataAnnotationsValidator />
<Wizard Id="DemoWizard" @ref="wizard">
<WizardStep StepModel="firstStepModel" Name="First Step">
<div class="form-group">
<label class="label">First name</label><span style="color:red;">*</span>
<InputText id="companyName" class="form-control" type="text" @bind-Value="@firstStepModel.FirstName"></InputText>
<ValidationMessage For="@(() => firstStepModel.FirstName)" />
</div>
<div class="form-group">
<label class="label">Last name</label><span style="color:red;">*</span>
<InputText id="companyName" class="form-control" type="text" @bind-Value="@firstStepModel.LastName"></InputText>
<ValidationMessage For="@(() => firstStepModel.LastName)" />
</div>
</WizardStep>
<WizardStep StepModel="companyModel" Name="Second Step">
<div class="form-group">
<label class="label"Company</label><span style="color:red;">*</span>
<InputText id="companyName" class="form-control" type="text" @bind-Value="@companyModel.CompanyName"></InputText>
<ValidationMessage For="@(() => companyModel.CompanyName)" />
</div>
</WizardStep>
<WizardStep StepModel="countryModel" Name="Final Step">
<div class="row">
<div class="row">
<div class="form-group">
<label class="label">Country</label><span style="color:red;">*</span>
<select id="country" class="form-control selectpicker" @bind="countryModel.CountryId">
<option value="">--select a country--</option>
@foreach (var country in countries)
{
<option value="@country.Id">@country.Name</option>
}
</select>
<ValidationMessage For="@(() => countryModel.CountryId)" />
</div>
</div>
</div>
</WizardStep>
</Wizard>
</EditForm>
背后的代码
public Wizard wizard;
protected EditForm editForm;
private FirstStepModel firstStepModel;
private CountryModel countryModel;
private CompanyModel companyModel;
private WizardViewModel wizardViewModel;
private List<Country> countries = new List<Country>();
public string StatusMessage { get; set; }
public string StatusClass { get; set; }
protected override async Task OnInitializedAsync()
{
wizardViewModel = new WizardViewModel();
wizardViewModel.CountryModel = new CountryModel();
wizardViewModel.CompanyModel = new CompanyModel();
wizardViewModel.FirstStepModel = new FirstStepModel();
countryModel = new CountryModel();
companyModel = new CompanyModel();
firstStepModel = new FirstStepModel();
countries.Add(new Country { Id = 1, Name = "Sweden" });
countries.Add(new Country { Id = 2, Name = "england" });
}
private async Task OnValidSubmit()
{
StatusClass = "alert-info";
StatusMessage = DateTime.Now + " Handle valid submit";
wizard.ActiveStep.StepCompleted = true;
}
private async Task OnInvalidSubmit()
{
StatusClass = "alert-danger";
StatusMessage = DateTime.Now + " Handle invalid submit";
wizard.ActiveStep.StepCompleted = false;
}
public class Country
{
public int Id { get; set; }
public string Name { get; set; }
}
public class CountryModel
{
[Required]
public int? CountryId { get; set; }
}
public class CompanyModel
{
[Required]
public string CompanyName { get; set; }
}
public class FirstStepModel
{
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
}
public class WizardViewModel
{
public FirstStepModel FirstStepModel { get; set; }
public CountryModel CountryModel { get; set; }
public CompanyModel CompanyModel { get; set; }
}
}
问题是当我单击向导中的“下一步”按钮或单击 firstStepModel.FirstName 的空“InputText”并将其留空然后单击时,“ValidationMessage”组件不会触发(或可见) firstStepModel.LastName 的“InputText”字段并在该字段旁边键入名称。
但是,当我再次在 FirstName 的“InputText”字段内单击时,键入一个名称,然后删除该名称并单击 InputText 字段外部,然后出现 ValidationMessages。
其余代码如下所示。
巫师剃刀
向导.razor.cs
public partial class Wizard
{
/// <summary>
/// List of <see cref="WizardStep"/> added to the Wizard
/// </summary>
protected internal List<WizardStep> Steps = new List<WizardStep>();
/// <summary>
/// The control Id
/// </summary>
[Parameter]
public string Id { get; set; }
public Object CurrentStepModelObject { get; set; }
/// <summary>
/// The ChildContent container for <see cref="WizardStep"/>
/// </summary>
[Parameter]
public RenderFragment ChildContent { get; set; }
/// <summary>
/// The Active <see cref="WizardStep"/>
/// </summary>
[Parameter]
public WizardStep ActiveStep { get; set; }
/// <summary>
/// The Index number of the <see cref="ActiveStep"/>
/// </summary>
[Parameter]
public int ActiveStepIx { get; set; }
/// <summary>
/// Determines whether the Wizard is in the last step
/// </summary>
public bool IsLastStep { get; set; }
/// <summary>
/// Sets the <see cref="ActiveStep"/> to the previous Index
/// </summary>
protected internal void GoBack()
{
if (ActiveStepIx > 0)
SetActive(Steps[ActiveStepIx - 1]);
}
/// <summary>
/// Sets the <see cref="ActiveStep"/> to the next Index
/// </summary>
protected internal void GoNext()
{
bool defaultValidatorSuccess = CheckValidationStatus(CurrentStepModelObject);
if (defaultValidatorSuccess)
{
ActiveStep.StepCompleted = true;
}
if (ActiveStepIx == Steps.Count - 1 && ActiveStep.StepCompleted)
{
if (defaultValidatorSuccess)
{
ActiveStep.StatusClass = "alert-info";
ActiveStep.StatusMessage = DateTime.Now + " Handle valid submit";
// last step, try save to database...
}
else
{
ActiveStep.StatusClass = "alert-danger";
ActiveStep.StatusMessage = DateTime.Now + " Handle invalid submit";
}
}
if (ActiveStepIx < Steps.Count - 1 && ActiveStep.StepCompleted)
{
SetActive(Steps[(Steps.IndexOf(ActiveStep) + 1)]);
}
}
/// <summary>
///
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
private bool CheckValidationStatus(Object obj)
{
//if all fields is ok
ValidationContext ctx = new ValidationContext(obj);
List<ValidationResult> results = new List<ValidationResult>();
bool _defaultvalidatorSuccess = Validator.TryValidateObject(obj, ctx, results);
return _defaultvalidatorSuccess;
}
/// <summary>
/// Populates the <see cref="ActiveStep"/> the Sets the passed in <see cref="WizardStep"/> instance as the
/// </summary>
/// <param name="step">The WizardStep</param>
protected internal void SetActive(WizardStep step)
{
ActiveStep = step ?? throw new ArgumentNullException(nameof(step));
CurrentStepModelObject = ActiveStep.StepModel;
ActiveStepIx = StepsIndex(step);
if (ActiveStepIx == Steps.Count - 1)
IsLastStep = true;
else
IsLastStep = false;
}
/// <summary>
/// Retrieves the index of the current <see cref="WizardStep"/> in the Step List
/// </summary>
/// <param name="step">The WizardStep</param>
/// <returns></returns>
public int StepsIndex(WizardStep step) => StepsIndexInternal(step);
protected int StepsIndexInternal(WizardStep step)
{
if (step == null)
throw new ArgumentNullException(nameof(step));
return Steps.IndexOf(step);
}
/// <summary>
/// Adds a <see cref="WizardStep"/> to the WizardSteps list
/// </summary>
/// <param name="step"></param>
protected internal void AddStep(WizardStep step)
{
Steps.Add(step);
}
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
SetActive(Steps[0]);
ActiveStep.StepCompleted = false;
StateHasChanged();
}
}
protected override async Task OnInitializedAsync()
{
CurrentStepModelObject = new object();
}
WizardStep.razor
@if (Parent.ActiveStep == this)
{
<div class="alert @StatusClass">@StatusMessage</div>
<div id="step-@(Parent.StepsIndex(this) + 1)">
@ChildContent
</div>
}
WizardStep.razor.cs
public partial class WizardStep
{
/// <summary>
/// The <see cref="Wizard"/> container
/// </summary>
[CascadingParameter]
protected internal Wizard Parent { get; set; }
public string StatusMessage { get; set; }
public string StatusClass { get; set;}
[Parameter]
public object StepModel { get; set; }
/// <summary>
/// The Child Content of the current <see cref="WizardStep"/>
/// </summary>
[Parameter]
public RenderFragment ChildContent { get; set; }
/// <summary>
/// The Name of the step
/// </summary>
[Parameter]
public string Name { get; set; }
public bool StepCompleted { get; set; }
protected override void OnInitialized()
{
Parent.AddStep(this);
}
}
有谁知道代码有什么问题?