Grid headers are misaligned if they are navigated in a scrolling scenario with a Frozen column.
===
ADMIN EDIT
===
The behavior affects the TreeList as well in a similar fashion. The misalignment is bigger when there is a frozen column but it is also reproducible without it in this demo.
In a Grid loaded with data made of ExpandoObject, set an aggregate GridAggregateType.Sum breaks the grouping feature while GridAggregateType Max, Min and Count work properly
Please find the attached project: in the grid on Index.razor grouping does not work, just comment Index.razor:43 to restore grouping feature
Exception message:
Error: System.InvalidOperationException: No generic method 'Sum' on type 'System.Linq.Enumerable' is compatible with the supplied type arguments and arguments. No type arguments should be provided if the method is non-generic.
at System.Linq.Expressions.Expression.FindMethod(Type type, String methodName, Type[] typeArgs, Expression[] args, BindingFlags flags)
at System.Linq.Expressions.Expression.Call(Type type, String methodName, Type[] typeArguments, Expression[] arguments)
at Telerik.DataSource.Expressions.EnumerableSelectorAggregateFunctionExpressionBuilder.CreateMethodCallExpression(LambdaExpression memberSelectorExpression)
at Telerik.DataSource.Expressions.EnumerableSelectorAggregateFunctionExpressionBuilder.CreateAggregateExpression()
at Telerik.DataSource.EnumerableSelectorAggregateFunction.CreateAggregateExpression(Expression enumerableExpression, Boolean liftMemberAccessToNull)
at Telerik.DataSource.Expressions.GroupDescriptorExpressionBuilder.<ProjectionPropertyValueExpressions>b__39_0(AggregateFunction f)
at System.Linq.Enumerable.SelectIListIterator`2.ToList()
at Telerik.DataSource.Expressions.GroupDescriptorExpressionBuilder.CreateProjectionInitExpression()
at Telerik.DataSource.Expressions.GroupDescriptorExpressionBuilder.CreateAggregateFunctionsProjectionMemberBinding()
at Telerik.DataSource.Expressions.QueryableAggregatesExpressionBuilder.CreateMemberBindings()+MoveNext()
at System.Collections.Generic.LargeArrayBuilder`1.AddRange(IEnumerable`1 items)
at System.Collections.Generic.EnumerableHelpers.ToArray[T](IEnumerable`1 source)
at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
at System.Dynamic.Utils.CollectionExtensions.ToReadOnly[T](IEnumerable`1 enumerable)
at System.Linq.Expressions.Expression.MemberInit(NewExpression newExpression, IEnumerable`1 bindings)
at Telerik.DataSource.Expressions.GroupDescriptorExpressionBuilder.CreateSelectBodyExpression()
at Telerik.DataSource.Expressions.GroupDescriptorExpressionBuilder.CreateSelectExpression()
at Telerik.DataSource.Expressions.GroupDescriptorExpressionBuilderBase.CreateQuery()
at Telerik.DataSource.Extensions.QueryableExtensions.Aggregate(IQueryable source, IEnumerable`1 aggregateFunctions)
at Telerik.DataSource.Extensions.QueryableExtensions.CreateDataSourceResult[TModel,TResult](IQueryable queryable, DataSourceRequest request, Func`2 selector)
at Telerik.DataSource.Extensions.QueryableExtensions.ToDataSourceResult(IQueryable queryable, DataSourceRequest request)
at Telerik.DataSource.Extensions.QueryableExtensions.ToDataSourceResult(IEnumerable enumerable, DataSourceRequest request)
at Telerik.Blazor.Data.TelerikDataSourceBase.ProcessData(IEnumerable data)
at Telerik.Blazor.Components.Common.DataBoundComponent`1.ProcessDataInternal()
at Telerik.Blazor.Components.Common.DataBoundComponent`1.ProcessDataAsync()
at Telerik.Blazor.Components.TelerikGrid`1.DataBoundProcessData()
at Telerik.Blazor.Components.TelerikGrid`1.ProcessDataAsync()
at Telerik.Blazor.Components.TelerikGrid`1.ApplyFiltersAsync()
at Telerik.Blazor.Components.TelerikGrid`1.OnFilterChange(FilterDescriptorBase filter)
at Telerik.Blazor.Components.Common.Filters.TelerikFilterHeader`1.Filter(FilterDescriptor filterDescriptor)
at Telerik.Blazor.Components.Common.Filters.TelerikFilterHeader`1.OnValueChanged(Object newValue)
at System.Threading.Tasks.Task.<>c.<ThrowAsync>b__139_0(Object state)
at Microsoft.AspNetCore.Components.Rendering.RendererSynchronizationContext.ExecuteSynchronously(TaskCompletionSource`1 completion, SendOrPostCallback d, Object state)
at Microsoft.AspNetCore.Components.Rendering.RendererSynchronizationContext.<>c.<.cctor>b__23_0(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location where exception was thrown ---
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at Microsoft.AspNetCore.Components.Rendering.RendererSynchronizationContext.ExecuteBackground(WorkItem item)
When you change the data source of the grid, it must re-render the data again.
For example, when you use a custom edit form, you add/edit the data with your own code and not through the grid. This is useful, for example, when you only want to show a few columns in the grid, but the model has many more editable fields. Or, when you want a customized layout/behavior of the edit form.
Minimum repro:
@
using
Telerik.Blazor.Components.Grid
@
using
Telerik.Blazor.Components.Button
<TelerikButton OnClick=
"@ChangeProduct"
>Works: Change an existing product</TelerikButton>
<TelerikButton OnClick=
"@AddProduct"
>Does not work: Add a
new
product</TelerikButton>
<TelerikButton OnClick=
"@RemoveProduct"
>Does not work: Remove an existing product</TelerikButton>
<TelerikGrid Data=@GridData
Pageable=
"true"
>
<TelerikGridColumns>
<TelerikGridColumn Field=@nameof(Product.ProductName) Title=
"Product Name"
/>
<TelerikGridColumn Field=@nameof(Product.UnitPrice) Title=
"Unit Price"
>
</TelerikGridColumn>
</TelerikGridColumns>
</TelerikGrid>
@functions {
public
List<Product> GridData {
get
;
set
; }
void
AddProduct()
{
GridData.Insert(0,
new
Product()
{
ProductId = DateTime.Now.Millisecond,
ProductName =
"some product name"
,
UnitPrice = DateTime.Now.Second
});
//after updating the data, the grid should show the item at the top of the first page.
//at the moment, you need to page, for example, for the data to be updated
}
protected
void
ChangeProduct()
{
GridData.Where(p => p.ProductId == 2).First().ProductName =
"changed at "
+ DateTime.Now;
}
protected
void
RemoveProduct()
{
GridData.RemoveAt(4);
//after updating the data, the grid should remove the fourth item immediately
//at the moment, you need to page, for example, for the data to be updated
}
protected
override
void
OnInit()
{
GridData =
new
List<Product>();
for
(
int
i = 0; i < 25; i++)
{
GridData.Add(
new
Product()
{
ProductId = i,
ProductName =
"Product"
+ i.ToString(),
UnitPrice = (
decimal
)(i * 3.14),
});
}
}
public
class
Product
{
public
string
ProductName {
get
;
set
; }
public
decimal
UnitPrice {
get
;
set
; }
public
int
ProductId {
get
;
set
; }
}
}
Occasionally I am getting TaskCancellation errors such as:
[13:07:52 ERR] Unhandled exception in circuit 'hQsJqY3F4XbTbzQETSggJClg_e4YRyQkrKHFMHCXugM'.
System.Threading.Tasks.TaskCanceledException: A task was canceled.
at Microsoft.JSInterop.JSRuntime.InvokeAsync[TValue](Int64 targetInstanceId, String identifier, Object[] args)
at Microsoft.JSInterop.JSRuntimeExtensions.InvokeVoidAsync(IJSRuntime jsRuntime, String identifier, Object[] args)
at Telerik.Blazor.Components.TelerikComboBox`2.Dispose()
at System.Threading.Tasks.Task.<>c.<ThrowAsync>b__140_0(Object state)
at Microsoft.AspNetCore.Components.Rendering.RendererSynchronizationContext.ExecuteSynchronously(TaskCompletionSource`1 completion, SendOrPostCallback d, Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Components.Rendering.RendererSynchronizationContext.ExecuteBackground(WorkItem item)
===========
ADMIN EDIT
===========
The error is related to a Microsoft bug. It occurs one minute after some client component has been disposed.
The exceptions are not bypassed due to memory leak. The bug is expected to be fixed in .NET 6 and this will be respected for the Telerik components, so that the errors do not appear.
I have a Grid using checkbox selection and when I un-check a row, the SelectedItemsChanged event is not firing. I'm using an async handler.
The problem appears to happen when a row is selected and then un-selected. The event is firing when it is selected but is not firing when it is un-selected.
<TelerikGrid Data="strategicLevelItems" SelectedItems="selectedStrategic" Width="100%" Height="500px"
ScrollMode="GridScrollMode.Scrollable" SelectionMode="GridSelectionMode.Multiple"
SelectedItemsChanged="@((IEnumerable<GetNavigationNodesModel> strategicItems) => OnStrategicSelectAsync(strategicItems))"
FilterMode="GridFilterMode.FilterRow">
<GridColumns>
<GridCheckboxColumn SelectAll="true" Width="40px" OnCellRender="@GridHelpers.CenterAlign" />
<GridColumn Field="@(nameof(GetNavigationNodesModel.Name))" />
</GridColumns>
</TelerikGrid>
private async Task OnStrategicSelectAsync(IEnumerable<GetNavigationNodesModel> selectedItems)
{
selectedStrategic = selectedItems;
var state = tacticalGrid.GetState();
var compositeFilter = new CompositeFilterDescriptor() { LogicalOperator = FilterCompositionLogicalOperator.Or };
foreach (var item in selectedItems)
{
compositeFilter.FilterDescriptors.Add(new FilterDescriptor()
{
Member = "ParentId",
Operator = FilterOperator.IsEqualTo,
Value = item.Id
});
}
state.FilterDescriptors.Clear();
state.FilterDescriptors.Add(compositeFilter);
await tacticalGrid.SetState(state);
}
Using mobile browser (Safari iOS or Chrome Android)
Go to demo grid page
https://demos.telerik.com/blazor-ui/grid/overview
Click any grid's filter menu which contains text field
Try to enter text into textbox.
The filter menu automatically closed, so you can't enter anything
---
ADMIN EDIT
this happens because the keyboard pops up, changes the screen size and may even scroll the page, and both of these events hide the popup menu.
A workaround could be using the filter row mode, with the caveat that it takes up more space on the initial rendering, and that filtering happens immediately.
---
Hi Telerik team,
When I want to bind the Blazor Grid to an ExpandoObject I need to assign the FieldType. I know I have to use non-nullable types.
But I want to use nullable types (for example int?) to have a blank cell within the Grid when there is no value for it. With "typeof(int)" instead of "typeof(int?)" every empty cell shows "0" which I don't want.
Is there any chance to let FieldType accept nullable types?
Best regards,
Rayko
If I add an await-ed call in the OnRowClick handler, then I cannot alter the grid state later in the code. It only works if the method is called again (e.g., a second click on the same row).
<AdminEdit>
This affects other Grid events too, for example, the PageChanged
</AdminEdit>
A workaround is to use synchronous code (remove the await call):
@inject IJSRuntime JsInterop
<TelerikGrid Data="@salesTeamMembers" OnRowClick="@OnRowClickHandler" @ref="@GridRef">
<DetailTemplate>
@{
var employee = context as MainModel;
<TelerikGrid Data="employee.Orders" Pageable="true" PageSize="5">
<GridColumns>
<GridColumn Field="OrderId"></GridColumn>
<GridColumn Field="DealSize"></GridColumn>
</GridColumns>
</TelerikGrid>
}
</DetailTemplate>
<GridColumns>
<GridColumn Field="Id"></GridColumn>
<GridColumn Field="Name"></GridColumn>
</GridColumns>
</TelerikGrid>
@code {
List<MainModel> salesTeamMembers { get; set; }
TelerikGrid<MainModel> GridRef { get; set; }
async Task OnRowClickHandler(GridRowClickEventArgs args) {
// After adding this line, it now requires a double click when the InvokeAsync call uses "await"
var width = JsInterop.InvokeAsync<int>("getWidth");
var model = args.Item as MainModel;
int index = salesTeamMembers.IndexOf(model);
//todo: you may want to take paging into account for example, or use js interop to get the index of the row based on contents from it like id
if (index > -1) {
var state = GridRef.GetState();
state.ExpandedRows = new List<int> { index };
await GridRef.SetState(state);
}
}
protected override void OnInitialized() {
salesTeamMembers = GenerateData();
}
private List<MainModel> GenerateData() {
List<MainModel> data = new List<MainModel>();
for (int i = 0; i < 5; i++) {
MainModel mdl = new MainModel { Id = i, Name = $"Name {i}" };
mdl.Orders = Enumerable.Range(1, 15).Select(x => new DetailsModel { OrderId = x, DealSize = x ^ i }).ToList();
data.Add(mdl);
}
return data;
}
public class MainModel {
public int Id { get; set; }
public string Name { get; set; }
public List<DetailsModel> Orders { get; set; }
}
public class DetailsModel {
public int OrderId { get; set; }
public double DealSize { get; set; }
}
}
When you scroll to the right in a grid and filter so that there are no items, the horizontal scroll disappears and you can no longer come back to the filter in order to clear it and work with the grid again.
1. Load a page with a Grid with Reorderable = true
2. While Grid is rendering load a different page
--> Unhandled ObjectDisposedException
Error: System.ObjectDisposedException: Cannot access a disposed object. Object name: 'DotNetObjectReference`1'. at Microsoft.JSInterop.DotNetObjectReference`1.ThrowIfDisposed() at Microsoft.JSInterop.JSRuntime.TrackObjectReference[TValue](DotNetObjectReference`1 dotNetObjectReference) at Microsoft.JSInterop.Infrastructure.DotNetObjectReferenceJsonConverter`1.Write(Utf8JsonWriter writer, DotNetObjectReference`1 value, JsonSerializerOptions options) at System.Text.Json.JsonSerializer.WriteDictionary[TProperty](JsonConverter`1 converter, JsonSerializerOptions options, WriteStackFrame& current, Utf8JsonWriter writer) at System.Text.Json.JsonPropertyInfoNotNullable`4.OnWriteDictionary(WriteStackFrame& current, Utf8JsonWriter writer) at System.Text.Json.JsonPropertyInfo.WriteDictionary(WriteStack& state, Utf8JsonWriter writer) at System.Text.Json.JsonSerializer.HandleDictionary(JsonClassInfo elementClassInfo, JsonSerializerOptions options, Utf8JsonWriter writer, WriteStack& state) at System.Text.Json.JsonSerializer.Write(Utf8JsonWriter writer, Int32 originalWriterDepth, Int32 flushThreshold, JsonSerializerOptions options, WriteStack& state) at System.Text.Json.JsonSerializer.WriteCore(Utf8JsonWriter writer, Object value, Type type, JsonSerializerOptions options) at System.Text.Json.JsonSerializer.WriteCore(PooledByteBufferWriter output, Object value, Type type, JsonSerializerOptions options) at System.Text.Json.JsonSerializer.WriteCoreString(Object value, Type type, JsonSerializerOptions options) at Microsoft.JSInterop.JSRuntime.InvokeAsync[TValue](String identifier, CancellationToken cancellationToken, Object[] args) at Microsoft.JSInterop.JSRuntime.InvokeWithDefaultCancellation[T](String identifier, Object[] args) at Telerik.Blazor.Components.Grid.GridHeaderRowBase`1.InitColumnReorderable() at Telerik.Blazor.Components.Grid.GridHeaderRowBase`1.OnAfterRenderAsync(Boolean firstRender) at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle)
You might have to try a few times to dispose the page at the correct time. With larger Grids it happens more frequently.
Grids without Reorderable = true do not throw an exception!
If I set grouping in OnStateInit, the GroupFooterTemplate does not have data for the aggregates I have set. If I group manually by dragging a column header, the data is there.
------
ADMIN EDIT: This stems from a framework behavior. The <GridAggregates> tag is a child component of the grid and as such, initializes after the grid. Since there is no event when all such child components are initialized the parent component cannot wait for them before starting to render and thus, it initializes before it can know what aggregates are defined.
Hi,
This relates to my forum post here: https://www.telerik.com/forums/grid-selection-performance
I've noticed that the grid becomes very slow to select a row and to page when there is more than a little data being displayed. In the test project attached it can take 9 seconds to just select a row on the grid which is unworkable. Although we can reduce the amount of data and use paging in the real application we are developing it is still far too slow for Production use.
The test application has 2 pages, one using the Telerik grid and one using a simple component that draws an HTML table and handles selection. My aim was to prove that the problem is not down to Blazor re-rendering when a row is selected. The simple component it is around 0.3 seconds to select a row vs 9 seconds for the Telerik grid.
Obviously I appreciate that the Telerik grid is doing a lot more than the component, but it is not just Blazor that is causing this issue, it must be related to the work the grid has to do when a row is selected.
The attached project has 2 pages, one using the Telerik Grid one using my simple component. Click the load button to generate 300 rows of test data and then try clicking on a row. You can see the problem by running a performance trace in either Firefox or Chrome. The browser can even become unresponsive just clicking on a row, which you will appreciate is impossible to live with. If that doesn't happen you can try increasing the amount of data generated.
Thanks for your time!
Kind Regards,
Nick.
When there are wide columns that produce a horizontal scrollbar, scrolling horizontally does not scroll the headers. It must.
WORKAROUND (see also the rules for the containing div that provides the scroll):
<style>
.k-grid,
.k-grid-container,
.k-grid-content.k-virtual-content {
display
: inline-
block
;
}
</style>
REPRODUCIBLE:
@
using
Telerik.Blazor.Components.Grid
<div style=
"width: 1200px; overflow-x: auto; overflow-y:hidden; border: 1px solid red;"
>
<TelerikGrid Data=
"@trades"
EditMode=
"inline"
Pageable=
true
PageSize=10>
<TelerikGridColumns>
<TelerikGridCommandColumn width=
"100"
>
<TelerikGridCommandButton Command=
"Edit"
Icon=
"edit"
>Edit</TelerikGridCommandButton>
<TelerikGridCommandButton Command=
"Update"
Icon=
"save"
ShowInEdit=
"true"
OnClick=
"UpdateItem"
>Update</TelerikGridCommandButton>
<TelerikGridCommandButton Command=
"Cancel"
Icon=
"cancel"
ShowInEdit=
"true"
OnClick=
"CancelItem"
>Cancel</TelerikGridCommandButton>
</TelerikGridCommandColumn>
<TelerikGridColumn Field=
"@(nameof(Trade.TradeId))"
Width=100></TelerikGridColumn>
@*<TelerikGridColumn Field=
"@(nameof(Trade.TradeType))"
Width=200></TelerikGridColumn>*@
<TelerikGridColumn Field=@nameof(Trade.TradeType) Title=
"Trade Type"
>
<EditorTemplate>
@{
var TradeToEdit = context
as
Trade;
if
(TradeToEdit.TradeType ==
"POWER PHYSICAL"
)
{
<select
class
=
"form-control d-inline"
style=
"height: 30px"
onchange=@SaveItem value=@TradeToEdit.TradeType>
<option value=
"POWER PHYSICAL"
>POWER PHYSICAL</option>
<option value=
"GAS PHYSICAL"
> GAS PHYSICAL</option>
</select>
}
else
{
<select
class
=
"form-control d-inline"
style=
"height: 30px"
onchange=@SaveItem value=@TradeToEdit.TradeType>
<option value=
"GAS PHYSICAL"
> GAS PHYSICAL</option>
<option value=
"POWER PHYSICAL"
>POWER PHYSICAL</option>
<option value=
"POWER PHYSICAL"
>POWER FINANCIAL</option>
</select>
}
}
</EditorTemplate>
</TelerikGridColumn>
<TelerikGridColumn Field=
"@(nameof(Trade.Company))"
Width=500></TelerikGridColumn>
<TelerikGridColumn Field=
"@(nameof(Trade.TradeDate))"
Width=500></TelerikGridColumn>
<TelerikGridColumn Field=
"@(nameof(Trade.BegTime))"
Width=500></TelerikGridColumn>
<TelerikGridColumn Field=
"@(nameof(Trade.EndTime))"
Width=500></TelerikGridColumn>
</TelerikGridColumns>
</TelerikGrid>
</div>
@functions {
public
class
Trade
{
public
int
TradeId {
get
;
set
; }
public
string
TradeType {
get
;
set
; }
public
string
Company {
get
;
set
; }
public
DateTime TradeDate {
get
;
set
; }
public
DateTime BegTime {
get
;
set
; }
public
DateTime EndTime {
get
;
set
; }
}
public
List<Trade> trades {
get
;
set
; }
protected
override
void
OnInit()
{
trades =
new
List<Trade>();
for
(
int
i = 0; i < 25; i++)
{
trades.Add(
new
Trade()
{
TradeId = i,
TradeType =
"type "
+ i,
Company =
"company "
+ i,
TradeDate = DateTime.Now.AddDays(i),
BegTime = DateTime.Now.AddHours(-i),
EndTime = DateTime.Now.AddHours(i)
});
}
}
void
SaveItem()
{
}
public
void
UpdateItem(GridCommandEventArgs e)
{
}
public
void
CancelItem(GridCommandEventArgs e)
{
}
}
In a filterable Grid, if a column is not bound to a field from the model the Grid uses, it throws with:
Error: System.ArgumentNullException: Value cannot be null. (Parameter 'nullableType')
Reproduction: https://blazorrepl.telerik.com/GyEUlFEs04AUJoJ601.
The issue is reproducible :
===
ADMIN EDIT
===
A possible workaround for the time being is to set the FieldType of the column: https://blazorrepl.telerik.com/wSugvFui10jhcpZy00.
Steps to reproduce:
1.Create a Telerik Grid with SelectionMode=@GridSelectionMode.Multiple and a GridCheckboxColumn to select/unselect the rows.
Also, bind the selected items to an IEnumerable collection and display the selected items in a <ul>
2.Click on Row1's checkbox - It selects the row, but not checking the checkbox
3.Click on it again- Now it unselects the row, but the checkbox is checked.
4.Click on the SelectAll checkbox in the grid header - It selects all rows, row checkboxes are checked, but the SelectAll checkbox in the grid header remains unchecked.
5.Click on the SelectAll checkbox again - All rows remain selected, row checkboxes remain checked, The SelectAll checkbox is now checked.
6.Click on the SelectAll checkbox again- All rows are unselected, row checkboxes are unchecked, The selectAll checkbox remains checked.
Another issue is, corresponding row checkbox remains checked on moving to next page eventhough the row is not selected.
For eg,
1. a grid of 20 rows displays 10 items per page; Row 2 is selected and checkbox is checked
2. Move to page 2 - Row 12 checkbox is checked (but row 12 is not selected)
Please note that this discrepancy is only when using a checkbox column, otherwise the grid selection using Ctrl + Click works as expected.
Attached Screenshot of one of the issues
On clicking Row 2 checkbox again, result below
Reproducible:
@using System.Collections.ObjectModel;
<div style="align-self:center;text-align:center" class="alert-danger">
@errorMessages
</div>
<div style="align-self:center;text-align:center" class="alert-success">
@successMessages
</div>
<TelerikGrid Data=@entitlementsExtended
Pageable="true"
Groupable="false"
PageSize="@PageSize"
OnUpdate="@UpdateHandler"
Sortable="false"
FilterMode="Telerik.Blazor.GridFilterMode.FilterMenu">
<GridColumns>
<GridColumn Field="@nameof(EntitlementValueDTOExtended.Description)" Editable="false" />
<GridColumn Field=@nameof(EntitlementValueDTOExtended.Value)>
<EditorTemplate>
@{
CurrentlyEditedEntitlement = context as EntitlementValueDTOExtended;
<div>
<TelerikDropDownList Data="@entitlementOptions" @bind-Value="CurrentlyEditedEntitlement.Value" Width="60px" PopupHeight="auto"></TelerikDropDownList>
</div>
}
</EditorTemplate>
</GridColumn>
<GridCommandColumn Width="300px">
<GridCommandButton Command="Save" Icon="save" ShowInEdit="true">Update</GridCommandButton>
<GridCommandButton Command="Edit" Icon="edit">Edit</GridCommandButton>
<GridCommandButton Command="Cancel" Icon="cancel" ShowInEdit="true">Cancel</GridCommandButton>
</GridCommandColumn>
</GridColumns>
</TelerikGrid>
@code {
int PageSize = 10;
public EntitlementValueDTOExtended CurrentlyEditedEntitlement { get; set; } = new EntitlementValueDTOExtended();
//changing this to List<> works
public ObservableCollection<EntitlementValueDTOExtended> entitlementsExtended { get; set; } = new ObservableCollection<EntitlementValueDTOExtended>();
public static List<string> entitlementOptions = new List<string> { "I", "E" };
public string errorMessages { get; set; } = "";
public string successMessages { get; set; } = "";
protected async override Task OnInitializedAsync()
{
IEnumerable<int> entitlements = Enumerable.Range(1, 50);
//this is a simplified workaround for people needing nested models
foreach (var entitlement in entitlements)
{
EntitlementValueDTOExtended entitlementExtended = new EntitlementValueDTOExtended();
entitlementExtended.Id = Guid.NewGuid();
entitlementExtended.Description = $"descr {entitlement}";
entitlementExtended.Value = $"value {entitlement}";
entitlementExtended.EntitlementTypeId = entitlement;
entitlementsExtended.Add(entitlementExtended);
}
StateHasChanged();
await base.OnInitializedAsync();
}
public async Task UpdateHandler(GridCommandEventArgs args)
{
EntitlementValueDTOExtended item = (EntitlementValueDTOExtended)args.Item;
var matchingItem = entitlementsExtended.FirstOrDefault(c => c.Id == item.Id);
if (matchingItem != null)
{
matchingItem.Description = item.Description;
matchingItem.EntitlementTypeId = item.EntitlementTypeId;
matchingItem.Value = item.Value;
}
successMessages = $"updated grid on {DateTime.Now}";
StateHasChanged();
}
public class EntitlementValueDTOExtended
{
public Guid Id { get; set; }
public string Description { get; set; } = "";
public string Value { get; set; } = "";
public int EntitlementTypeId { get; set; } = 0;
}