Blazor Child to Parent EventCallback<List<string>> 未触发
Blazor Child to Parent EventCallback<List<string>> not triggering
我正在 Blazor 服务器端为多 select 下拉菜单创建一个共享组件。 SelectMultiple.razor 子组件未将 selected 值传递回父 index.razor 页面。子组件中的 EventCallback SelectedItemChanged 似乎没有触发。谁能帮帮我吗?
下面是SelectMultiple.razor
<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;
}
这是我的 index.razor
@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()
函数。你可以从这里算出剩下的。
这个docs article explains the basics around parameter binding in Blazor. Also, check the answers to ,他们可能更容易理解一些。
我正在 Blazor 服务器端为多 select 下拉菜单创建一个共享组件。 SelectMultiple.razor 子组件未将 selected 值传递回父 index.razor 页面。子组件中的 EventCallback SelectedItemChanged 似乎没有触发。谁能帮帮我吗?
下面是SelectMultiple.razor
<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;
}
这是我的 index.razor
@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()
函数。你可以从这里算出剩下的。
这个docs article explains the basics around parameter binding in Blazor. Also, check the answers to