I'm working on a custom component based on RadzenDataGrid
that allows row selection by range (similar to how Windows Explorer works with Shift + click). Internally, the logic works fine — the "Value" variable gets updated correctly with the selected items.
@typeparam TItem
<RadzenDataGrid@ref="_dataGrid"
Data="@Data"
TItem="TItem"
AllowColumnResize="true"
AllowSorting="true"
SelectionMode="DataGridSelectionMode.Multiple"
PageSize="10"
Value="@Value"
ValueChanged="@ValueChanged"
CellClick="OnRowClick">
<Columns>
@ChildContent
</Columns>
</RadzenDataGrid>
@code {
[Parameter]
public RenderFragment ChildContent { get; set; } = default!;
[Parameter]
public IEnumerable<TItem> Data { get; set; } = Enumerable.Empty<TItem>();
[Parameter]
public IList<TItem> Value { get; set; } = new List<TItem>();
[Parameter]
public EventCallback<IList<TItem>> ValueChanged { get; set; }
private RadzenDataGrid<TItem> _dataGrid;
private TItem? _startRow;
private async Task OnRowClick(DataGridCellMouseEventArgs<TItem> args)
{
if (args.ShiftKey && _startRow != null)
{
await SelectRange(args);
return;
}
_startRow = args.Data;
if (Value.Contains(args.Data))
{
Value.Remove(args.Data);
}
else
{
Value.Add(args.Data);
}
if (ValueChanged.HasDelegate)
{
await ValueChanged.InvokeAsync(Value);
}
await InvokeAsync(() => _dataGrid.Reload());
}
private async Task SelectRange(DataGridCellMouseEventArgs<TItem> args)
{
if (_startRow == null || args.Data == null)
return;
var dataList = Data.ToList();
var startIndex = dataList.IndexOf(_startRow);
var endIndex = dataList.IndexOf(args.Data);
if (startIndex == -1 || endIndex == -1)
return;
if (startIndex > endIndex)
(startIndex, endIndex) = (endIndex, startIndex);
Value.Clear();
for (var i = startIndex; i <= endIndex; i++)
{
var rowData = dataList[i];
if (!Value.Contains(rowData))
Value.Add(rowData);
}
if (ValueChanged.HasDelegate)
{
await ValueChanged.InvokeAsync(Value);
}
await InvokeAsync(() => _dataGrid.Reload());
}
}
@page "/demo-grid"
<h3 class="mb-4 text-xl font-semibold">Demo de SelectableDataGrid</h3>
<Test TItem="Person"
Data="@people"
@bind-Value="@selectedEmployees">
<RadzenDataGridColumn TItem="Person" Property="Name" Title="Nombre" />
<RadzenDataGridColumn TItem="Person" Property="Age" Title="Edad" />
<RadzenDataGridColumn TItem="Person" Property="City" Title="Ciudad" />
</Test>
@if (selectedEmployees?.Any() == true)
{
<h4 class="mt-4 text-lg font-semibold">Empleados seleccionados:</h4>
<ul class="list-disc list-inside">
@foreach (var emp in selectedEmployees)
{
<li>
<strong>@emp.Name</strong><br />
Edad: @emp.Age<br />
Ciudad: @emp.City
</li>
}
</ul>
}
@code {
IList<Person> selectedEmployees = new List<Person>();
private List<Person> people = new()
{
new Person { Name = "Ana", Age = 30, City = "Madrid" },
new Person { Name = "Luis", Age = 45, City = "Barcelona" },
new Person { Name = "Carla", Age = 27, City = "Sevilla" },
new Person { Name = "Juan", Age = 35, City = "Valencia" }
};
public class Person
{
public string Name { get; set; } = string.Empty;
public int Age { get; set; }
public string City { get; set; } = string.Empty;
}
}
It seems like the @bind-Value is not updating the selectedEmployees list as expected. Even though the Value inside the component has the correct selected data, the changes are not reflected outside.
Any ideas on what might be going wrong or how to ensure two-way binding works properly in this case?