Reputation: 986
I created a C# project using Blazor and Devexpress DxDataGrid component to create a Master Detail View. Everything works fine using the default command buttons (New, Edit). When I replace the Master command default buttons with icons, I have no problem with the edition functions:
When I replace the detail default controls, the detail editor for adding or replacing rows doesn´t work:
When I keep the default command buttons, just for the detail, the master (with icons) and detail (with default buttons), all the master and detail editors works fine:
To reproduce the issue, please download and compile the devexpress project you can find at: How to replace default command button with icons on DXDataGrid The example shows how to replace the default buttons in a single grid. In my test project I added a detail as it´s shown in the following piece of code (just replace all code in .razor file):
@page "/"
@using CommandButtonsWithIcons.Data
@inject WeatherForecastService ForecastService
@if (forecasts == null) {
<h1>Loading...</h1>
}
else {
<DxDataGrid Data=@forecasts ShowFilterRow=false CssClass="MainGrid" @ref="MyGrid" ShowDetailRow="true"
RowUpdating=@((updatingDataItem, newValues) => OnRowUpdating(updatingDataItem, newValues))
RowInserting=@((newValues) => OnRowInserting(newValues))>
<Columns>
<DxDataGridCommandColumn>
<HeaderCellTemplate>
<a class="oi oi-plus" @onclick="@(() => MyGrid.StartRowEdit(null))" href="javascript:void(0);"></a>
</HeaderCellTemplate>
<CellTemplate>
<a class="oi oi-pencil" @onclick="@(() => MyGrid.StartRowEdit(context))" href="javascript:void(0);"></a>
<a class="oi oi-x" @onclick="@(() => Delete(context as WeatherForecast))" href="javascript:void(0);"></a>
</CellTemplate>
</DxDataGridCommandColumn>
<DxDataGridColumn Field=@nameof(WeatherForecast.TemperatureC) Caption="Temp. (C)"></DxDataGridColumn>
<DxDataGridColumn Field=@nameof(WeatherForecast.TemperatureF) Caption="Temp. (F)"></DxDataGridColumn>
<DxDataGridComboBoxColumn Field=@nameof(WeatherForecast.Summary) Caption="Summary" Data=@summaries></DxDataGridComboBoxColumn>
<DxDataGridDateEditColumn Field=@nameof(WeatherForecast.Date) DisplayFormatString="dd/MM/yyyy"
EditFormatString="dd/MM/yyyy"></DxDataGridDateEditColumn>
</Columns>
<DetailRowTemplate Context="dataItem">
<DxDataGrid [email protected](x=>x.TemperatureC==dataItem.TemperatureC) ShowFilterRow=false CssClass="MainGrid" @ref="MyGridDetail"
RowUpdating=@((updatingDataItem, newValues) => OnRowUpdating(updatingDataItem, newValues))
RowInserting=@((newValues) => OnRowInserting(newValues))>
<DxDataGridCommandColumn>
<HeaderCellTemplate>
<a class="oi oi-plus" @onclick="@(() => MyGridDetail.StartRowEdit(null))" href="javascript:void(0);"></a>
</HeaderCellTemplate>
<CellTemplate>
<a class="oi oi-pencil" @onclick="@(() => MyGridDetail.StartRowEdit(context))" href="javascript:void(0);"></a>
<a class="oi oi-x" @onclick="@(() => Delete(context as WeatherForecast))" href="javascript:void(0);"></a>
</CellTemplate>
</DxDataGridCommandColumn>
<DxDataGridColumn Field=@nameof(WeatherForecast.TemperatureC) Caption="Temp. (C)"></DxDataGridColumn>
<DxDataGridColumn Field=@nameof(WeatherForecast.TemperatureF) Caption="Temp. (F)"></DxDataGridColumn>
<DxDataGridComboBoxColumn Field=@nameof(WeatherForecast.Summary) Caption="Summary" Data=@summaries></DxDataGridComboBoxColumn>
<DxDataGridDateEditColumn Field=@nameof(WeatherForecast.Date) DisplayFormatString="dd/MM/yyyy"
EditFormatString="dd/MM/yyyy"></DxDataGridDateEditColumn>
</DxDataGrid>
</DetailRowTemplate>
</DxDataGrid>
}
@functions {
WeatherForecast[] forecasts;
string[] summaries;
DevExpress.Blazor.DxDataGrid<WeatherForecast> MyGrid;
DevExpress.Blazor.DxDataGrid<WeatherForecast> MyGridDetail;
protected override async Task OnInitializedAsync() {
forecasts = await ForecastService.GetForecastAsync();
summaries = await ForecastService.GetSummariesAsync();
}
async void OnRowUpdating(WeatherForecast dataItem, Dictionary<string, object> newValue) {
forecasts = await ForecastService.Update(dataItem, newValue);
}
async void OnRowInserting(Dictionary<string, object> newValue) {
forecasts = await ForecastService.Insert(newValue);
}
async void Delete(WeatherForecast item) {
if (item != null) {
forecasts = await ForecastService.Remove(item);
}
}
}
UPDATE As Paul V from devexpress suggests, we have to create a new razor component that implements a new DXDatagrid component instance, since it is not suitable to reference the component, 2 or more times on the same razor component. So, to fix the problem, create another component (ie. DetaiGrid) and reference it inside DetailRowTemplate and send a a parameter, the master record and the detail source :
<DetailRowTemplate Context="dataItem">
<DetailGrid MasterRecord="@dataItem" ForecastService="@ForecastService" Forecasts="@forecasts" ></DetailGrid>
</DetailRowTemplate>
Detail Example:
<h3>DetailGrid2</h3>
@using CommandButtonsWithIcons.Data
<DxDataGrid [email protected](x=>x.TemperatureC==MasterRecord.TemperatureC) ShowFilterRow=false CssClass="MainGrid" @ref="MyGridDetail"
RowUpdatingAsync=@(OnRowUpdating)
RowInsertingAsync=@(OnRowInserting)>
<DxDataGridCommandColumn>
<HeaderCellTemplate>
<a class="oi oi-plus" @onclick="@(() => MyGridDetail.StartRowEdit(null))" href="javascript:void(0);"></a>
</HeaderCellTemplate>
<CellTemplate>
<a class="oi oi-pencil" @onclick="@(() => MyGridDetail.StartRowEdit(context))" href="javascript:void(0);"></a>
</CellTemplate>
</DxDataGridCommandColumn>
<DxDataGridColumn Field=@nameof(WeatherForecast.TemperatureC) Caption="Temp. (C)"></DxDataGridColumn>
<DxDataGridColumn Field=@nameof(WeatherForecast.TemperatureF) Caption="Temp. (F)"></DxDataGridColumn>
<DxDataGridDateEditColumn Field=@nameof(WeatherForecast.Date) DisplayFormatString="dd/MM/yyyy"
EditFormatString="dd/MM/yyyy"></DxDataGridDateEditColumn>
</DxDataGrid>
@code {
[Parameter]
public WeatherForecast[] Forecasts { get; set; }
[Parameter]
public WeatherForecast MasterRecord{ get; set; }
[Parameter]
public WeatherForecastService ForecastService { get; set; }
DevExpress.Blazor.DxDataGrid<WeatherForecast> MyGridDetail = null;
async Task OnRowUpdating(WeatherForecast dataItem, IDictionary<string, object> newValue)
{
Forecasts = await ForecastService.Update(dataItem, newValue);
}
async Task OnRowInserting(IDictionary<string, object> newValue)
{
//forecasts = await ForecastService.Insert(newValue);
}
}
Upvotes: 3
Views: 2077
Reputation: 110
I do not recommend using one ref variable for several instances. It may cause such collisions. Isolate your detail grid in a separate component to resolve the issue.
Upvotes: 3