Duplicated
Last Updated: 02 Mar 2020 13:22 by ADMIN
Shaun
Created on: 12 May 2019 16:53
Category: Grid
Type: Bug Report
1
Column Sorting breaks under subclassing scenarios

Consider the following scenario:

<TelerikGrid Data="Animals" Sortable="true">
  <TelerikGridColumns>
    <TelerikGridColumn Field="Color"></TelerikGridColumn>
    <TelerikGridColumn Field="Breed"></TelerikGridColumn>
  </TelerikGridColumns>
</TelerikGrid>

@functions {
  public List<Animal> Animals { get; set; } = new List<Animal> { new Dog { Breed = "Sheepdog", Color = "Black" } };

  public class Animal { public string Color { get; set; } }
  public class Dog : Animal { public string Breed { get; set; } }
}

Everything renders fine for the grid until you attempt to sort by Breed, which results in the following exception:

System.ArgumentException: Invalid property or field - 'Breed' for type: Animal
   at Telerik.DataSource.Expressions.MemberAccessTokenExtensions.CreateMemberAccessExpression(IMemberAccessToken token, Expression instance)

 

Not sure what is going on under the hood here, but perhaps this could be fixed by looking at the type of the object, rather than the underlying list?    I'm aware that this can be fixed by changing the data source to List<Dog> , but I think this use case of using a base-class is useful for many dynamic scenarios (think dynamic columns, etc)

Duplicated
This item is a duplicate of an already existing item. You can find the original item here:
2 comments
ADMIN
Marin Bratanov
Posted on: 03 Oct 2019 08:43

For anyone finding this page, this has been reopened due to popular demand, with a broader spectrum: https://feedback.telerik.com/blazor/1432615-support-for-nested-complex-models.

 

Regards,
Marin Bratanov
Progress Telerik

 UI for Blazor
ADMIN
Marin Bratanov
Posted on: 13 May 2019 06:30
Hello Shaun,

Generally, in such a case the grid must be bound to a parent class/interface that exposes all fields that its inheritors will have, so that the grid can show them. The grid cannot know what may be inherited and how its values relate to the base type it is bound to.

Thus, my best advice is to have all necessary fields in the base class and override them in child classes if needed, otherwise, return an empty string in the main class.

An alternative approach is to:

  1. implement templates for the grid in order to show the correct field (see here for a similar example), 
  2. and to implement IComparable in those classes so that they can be sorted, as code outside those classes cannot otherwise know how to order them.

Here's an example I made for you of the latter:

@using Telerik.Blazor.Components.Grid
<TelerikGrid Data="Animals" Sortable="true">
    <TelerikGridColumns>
        <TelerikGridColumn Field="Color"></TelerikGridColumn>
        <TelerikGridColumn Title="Breed">
            <Template>
                @{
                    if (context is Dog)
                    {
                        @((context as Dog).Breed)
                    }
                    else if (context is Cat)
                    {
                        @((context as Cat).Cuteness)
                    }
                }
            </Template>
        </TelerikGridColumn>
    </TelerikGridColumns>
</TelerikGrid>
 
@functions {
    public List<Animal> Animals { get; set; } = new List<Animal> {
        new Dog { Breed = "Sheepdog", Color = "Black" },
        new Dog { Breed = "Collie", Color = "Tan" },
        new Cat { Color = "tuxedo", Cuteness = "maximum" }
    };
 
    public class Animal { public string Color { get; set; } }
    public class Dog : Animal, IComparable
    {
        public string Breed { get; set; }
 
        public int CompareTo (object obj)
        {
            if(obj is Dog)
            {
                return this.Breed.CompareTo((obj as Dog).Breed);
            }
            else if (obj is Cat)
            {
                return this.Breed.CompareTo((obj as Cat).Cuteness);
            }
            throw new ArgumentException("Object is not a type I can compare");
        }
    }
    public class Cat : Animal, IComparable
    {
        public string Cuteness { get; set; }
 
        public int CompareTo (object obj)
        {
            if(obj is Dog)
            {
                return this.Cuteness.CompareTo((obj as Dog).Breed);
            }
            else if (obj is Cat)
            {
                return this.Cuteness.CompareTo((obj as Cat).Cuteness);
            }
            throw new ArgumentException("Object is not a type I can compare");
        }
    }
}

 


Regards,
Marin Bratanov
Progress Telerik UI for Blazor