链接到 GitHub 以快速访问最小可重现示例(下面也提供了代码):https://github.com/thecodeiackiller/cascadingSelectListProblem
注意:对于那些不熟悉健身领域的人,在给定的锻炼中,您通常有一种锻炼类型(腿部训练、上半身等),并且在该锻炼中,您有锻炼类型(您的主要/较重锻炼、您的辅助练习和辅助练习(锻炼小肌肉)。
预期用户流量:
问题:第二行的练习名称列表不会更新。尽管练习类型不同,练习名称列表仍与第一个练习相同,这应该会更改显示的练习。
我当前实现的AddWorkout.razor组件:
@using stateManagementMinimumReproducibleExample.Repositories
@using stateManagementMinimumReproducibleExample.Models
@page "/addworkout"
@rendermode InteractiveServer
@inject UserExerciseRepository userExerciseRepository
<EditForm Model="userExercise">
<label for="workoutType"> Workout Type: </label>
<InputSelect id="workoutType" @bind-Value="userExercise.WorkoutType" @bind-Value:after="GetExercisesByWorkoutType">
@foreach (var type in Enum.GetValues(typeof(WorkoutType)))
{
<option value="@type">@type</option>
}
</InputSelect>
@for (int i = 0; i < numberOfExercisesInWorkout; i++)
{
var j = i;
if (j >= exerciseListForSelectedDay.Count)
{
exerciseListForSelectedDay.Add(new UserExercise());
}
<div>
<label for="exerciseType"> Exercise Type: </label>
<InputSelect id="exerciseType" @bind-Value="exerciseListForSelectedDay[j].ExerciseType" @bind-Value:after="GetExercisesByExerciseType">
@foreach (var type in Enum.GetValues(typeof(ExerciseType)))
{
<option value="@type">@type</option>
}
</InputSelect>
<label for="exerciseName"> Exercise: </label>
<InputSelect id="exerciseName" @bind-Value="exerciseListForSelectedDay[j].ExerciseId">
@foreach (var exercise in listOfExerciseByExerciseType)
{
<option value="@exercise.Id">@exercise.Name</option>
}
</InputSelect>
</div>
}
</EditForm>
@code {
private int numberOfExercisesInWorkout = 2;
private UserExercise userExercise = new();
private List<UserExercise> exerciseListForSelectedDay = new();
public List<Exercise> listOfExercisesByWorkoutType = new();
public List<Exercise> listOfExerciseByExerciseType = new();
public async Task GetExercisesByWorkoutType()
{
listOfExercisesByWorkoutType = await userExerciseRepository.GetExercisesBasedOnWorkoutType(userExercise.WorkoutType);
StateHasChanged();
}
public void GetExercisesByExerciseType()
{
listOfExerciseByExerciseType = userExerciseRepository.GetExercisesFromWorkoutListBasedOnExerciseType(listOfExercisesByWorkoutType, userExercise.ExerciseType);;
}
}
我考虑过创建一个字典来存储锻炼中每个练习的练习列表的可能性。此外,我考虑过将列表存储为 UserExercise 类中的属性,然后将筛选后的练习列表添加到该属性中。我不确定我到底应该走哪条路,或者是否有任何潜在的特定于 Blazor 的状态管理替代方案。
上面的代码应该为您提供足够的信息来诊断问题。如果您需要视觉效果,请按照以下步骤在分叉和克隆 GitHub 存储库后快速重现问题:
此时,您将看到基于选择与第一行不同的锻炼类型,第二行的过滤列表尚未更新。我怎样才能获得第二次(及以后)出现的适当练习列表? 谢谢你。
您可以尝试以下代码来解决该问题:
添加锻炼.razor:
@using stateManagementMinimumReproducibleExample.Repositories
@using stateManagementMinimumReproducibleExample.Models
@page "/addworkout"
@rendermode InteractiveServer
@inject UserExerciseRepository userExerciseRepository
<EditForm Model="userExercise">
<label for="workoutType"> Workout Type: </label>
<InputSelect id="workoutType" @bind-Value="userExercise.WorkoutType" @bind-Value:after="GetExercisesByWorkoutType">
@foreach (var type in Enum.GetValues(typeof(WorkoutType)))
{
<option value="@type">@type</option>
}
</InputSelect>
@for (int i = 0; i < numberOfExercisesInWorkout; i++)
{
var j = i;
if (j >= exerciseListForSelectedDay.Count)
{
exerciseListForSelectedDay.Add(new UserExercise());
}
<div>
<label for="exerciseType"> Exercise Type: </label>
<InputSelect id="exerciseType" @bind-Value="exerciseListForSelectedDay[j].ExerciseType" @bind-Value:after="() => GetExercisesByExerciseType(j)">
@foreach (var type in Enum.GetValues(typeof(ExerciseType)))
{
<option value="@type">@type</option>
}
</InputSelect>
<label for="exerciseName"> Exercise: </label>
<InputSelect id="exerciseName" @bind-Value="exerciseListForSelectedDay[j].ExerciseId">
@foreach (var exercise in exerciseListForSelectedDay[j].FilteredExercises)
{
<option value="@exercise.Id">@exercise.Name</option>
}
</InputSelect>
</div>
}
</EditForm>
@code {
private int numberOfExercisesInWorkout = 2;
private UserExercise userExercise = new();
private List<UserExercise> exerciseListForSelectedDay = new();
public List<Exercise> listOfExercisesByWorkoutType = new();
public async Task GetExercisesByWorkoutType()
{
listOfExercisesByWorkoutType = await userExerciseRepository.GetExercisesBasedOnWorkoutType(userExercise.WorkoutType);
// Update each exercise list based on the new workout type
foreach (var exercise in exerciseListForSelectedDay)
{
exercise.FilteredExercises = userExerciseRepository.GetExercisesFromWorkoutListBasedOnExerciseType(listOfExercisesByWorkoutType, exercise.ExerciseType);
}
StateHasChanged();
}
public async Task GetExercisesByExerciseType(int index)
{
// Filter the exercises based on the ExerciseType for the specific row (index)
var selectedExerciseType = exerciseListForSelectedDay[index].ExerciseType;
exerciseListForSelectedDay[index].FilteredExercises = userExerciseRepository.GetExercisesFromWorkoutListBasedOnExerciseType(listOfExercisesByWorkoutType, selectedExerciseType);
await InvokeAsync(StateHasChanged);
}
}
UserExercise.cs:
namespace stateManagementMinimumReproducibleExample.Models
{
public class UserExercise
{
public int Id { get; set; }
public int ExerciseId { get; set; }
public ExerciseType ExerciseType { get; set; }
public WorkoutType WorkoutType { get; set; }
// Add this property to store the filtered exercises for each row
public List<Exercise> FilteredExercises { get; set; } = new List<Exercise>();
}
}
所以基本上,在您的代码中,您尝试全局更新列表,并且它使用单个列表,因此您看到了相同的练习。为了避免这个问题,您可以为行创建单独的过滤器列表。
结果: