我正在Blazor服务器端为多选下拉列表创建一个共享组件。SelectMultiple.rarzor子组件没有将选定的值传递回父index.razor页面。事件回调<列表>子组件中的SelectedItemChanged似乎未触发。有人能帮我吗?
下面是SelectMultiple.rarzor
<div>
<div class="form-group mb-1">
<button class="btn dropdown-toggle btn-light"
@onclick="@ToggleSelectMultiple"
title="@SelectedItemsText">
@ButtonText
</button>
</div>
<div hidden="@toggleSelectBox" class="border border-secondary rounded py-1">
<div class="mx-1">
<input class="form-control" @bind="FilterText" @bind:event="oninput" />
</div>
<div class="form-check mt-1">
@foreach (var item in FilteredItems)
{
<label>
<input type="checkbox" class="mr-1" checked="@item.IsSelected"
@onchange="_e => { FilteredItemChanged(item.Item, _e.Value); }" />@item.Item
</label><br />
}
</div>
</div>
</div>
@code{
//public class SelectedItem
//{
// public string Item { get; set; }
// public bool IsSelected { get; set; }
//}
private string _filterText;
private bool toggleSelectBox = true;
private List<string> _selectedItems;
[Parameter] public List<string> Elements { get; set; }
[Parameter]
public List<string> SelectedItems
{
get => _selectedItems;
set
{
_selectedItems = value;
SelectedItemChanged.InvokeAsync(SelectedItems);
}
}
[Parameter] public EventCallback<List<string>> SelectedItemChanged { get; set; }
public List<SelectedItem> FilteredItems { get; set; } = new();
public string FilterText
{
get { return _filterText; }
set
{
_filterText = value;
if (!string.IsNullOrWhiteSpace(FilterText))
{
FilteredItems = Elements.Where(x => x.ToLower().Contains(FilterText))
.Select(x => new SelectedItem() { Item = x, IsSelected = SelectedItems.Contains(x) }).ToList();
}
else
{
FilteredItems = Elements.Select(x => new SelectedItem() { Item = x, IsSelected = SelectedItems.Contains(x) }).ToList();
}
}
}
public string SelectedItemsText { get; set; }
public string ButtonText { get; set; } = "Nothing selected";
protected override void OnInitialized()
{
Elements.ForEach(x => FilteredItems.Add(new SelectedItem() { Item = x }));
base.OnInitialized();
}
public void FilteredItemChanged(string item, object checkedValue)
{
if ((bool)checkedValue)
{
SelectedItems.Add(item);
}
else
{
SelectedItems.Remove(item);
}
SelectedItemsText = SelectedItems.Any() ? string.Join(",", SelectedItems.Select(x => x)) : null;
ButtonText = SelectedItems.Any()
? (SelectedItems.Count == 1 ? SelectedItemsText : $"{SelectedItems.Count} items selected")
: "Nothing selected";
StateHasChanged();
}
private void ToggleSelectMultiple()
{
toggleSelectBox = !toggleSelectBox;
ClearSearchText();
}
private void ClearSearchText() => FilterText = null;
}
这是我的刮胡刀
@page "/"
<SelectMultiple Elements="Elements" SelectedItems="SelectedElements" SelectedItemChanged="SelectionChanged" />
<p>@SelectionAsText</p>
@code{
public List<string> Elements { get; set; } = new List<string>() { "dog", "cat", "mouse", "hippo", "rat", "giraffe" };
public List<string> SelectedElements { get; set; } = new();
private string SelectionAsText;
public void SelectionChanged()
{
SelectionAsText = string.Join(",", SelectedElements);
}
}
之所以会发生这种情况,是因为只有当List<string>
变量发生变化时才会引发事件,而在组件初始化期间,代码中这种情况只发生一次。
混淆的原因是,在整个组件的生命周期中,这个List
变量指向同一个对象,因此它不会更改。是的,该列表的内容发生了变化,但对List
本身的引用没有变化。
首先,我建议将InvokeAsync()
添加到FilteredItemChanged()
函数中。你可以从这里算出其余的。
这篇文档文章解释了Blazor中参数绑定的基础知识。此外,检查这个SO问题的答案,它们可能更容易理解。