We use cookies to give you the best experience on our website. If you continue to browse, then you agree to our privacy policy and cookie policy. Image for the cookie policy date

Grid ColumnTemplates: Dictionary values lost in context object

Hello everyone,

a while ago I opened another thread, stating how the EjsGrid has problems converting Guids: ColumnTemplate InvalidCastException GUID type property 

While fiddling around to find a way to make it work with Guids somehow, I also noticed that the Grid has problems keeping the data of a property of with a Dictionary as type. When specifying a ColumnTemplate for the specific property, the context object somehow loses all values of the Dictionary. Here is how I tested this:

I posted the code as links to paste bin, as I did not find out how to include the code here directly.

Setup code:

Grid definition:

Result:

When stepping into the template code inside Visual Studio, the dictionary appears to be empty:


 But the Dictionary is filled correctly in the original data source:


Is there a way to work around this / Could you help with fixing this?

Best Regards,

Karl


12 Replies

RN Rahul Narayanasamy Syncfusion Team August 14, 2019 12:00 PM UTC

Hi Karl, 
 
Greetings from Syncfusion. 

We are able to reproduce the reported issue at our end and we have confirmed it is bug from our side. We have logged defect “dictionary values are not properly serialized in grid templates” report for the same. Thank you for taking the time to report this issue and helping us improve our product. At Syncfusion, we are committed to fixing all validated defects (subject to technological feasibility and Product Development Life Cycle ) and including the defect fix in our next Nuget release which is expected to be roll out on August 31, 2019. 
  
You can now track the current status of your request, review the proposed resolution timeline, and contact us for any further inquiries through this link. 
  
  
Till then we appreciate your patience. 

Regards, 
Rahul 



CW Christoph Weller August 14, 2019 02:07 PM UTC

Hi Karl,

I don't think that this is an bug. You make an error when debugging, i saw it on the picture you have attached. You look onto the variable person, but on this time the variable person has not not been updated by the variable context. You must look on the variable context and then you will see there that the dictionary is filled up as expected.

Best regards
Christoph Weller


KP Karl Posch August 16, 2019 09:16 AM UTC

Hello Christoph,

thanks for your reply. My screenshot was a bit unclear. The breakpoint is set at "var additionalDataString =.... " hence the initialization of the person field was done already.

Maybe this is a better picture to show that the Dictionary is already empty inside the context object:



Best Regards,

Karl


VN Vignesh Natarajan Syncfusion Team August 19, 2019 12:43 PM UTC

Hi Karl / Christopher,  

We have confirmed it is bug from our side. We have logged defect “dictionary values are not properly serialized in grid templates” report for the same. Thank you for taking the time to report this issue and helping us improve our product. At Syncfusion, we are committed to fixing all validated defects (subject to technological feasibility and Product Development Life Cycle ) and including the defect fix in our next Nuget release which is expected to be roll out on August 31, 2019.  
   
You can now track the current status of your request, review the proposed resolution timeline, and contact us for any further inquiries through this link.  
   
   
Till then we appreciate your patience.  

Regards,  
Vignesh Natarajan.


RN Rahul Narayanasamy Syncfusion Team September 4, 2019 12:53 PM UTC

Hi Karl/Christopher,  

We are glad to inform that our latest Nuget package (17.2.0.49-beta) has been successfully rolled out. Please find the latest Nuget package from below   

 
Please find the release notes from below link for the changes and fixes we have included in this release  

 
In this release we have included the fix for the issue “dictionary values are not properly serialized in grid templates. We have also ensured the reported issue by checking the sample to latest NuGet. For your convenience we have attached the sample with updated NuGet package. 
 
 
Please get back to us if you have further queries. 
 
Regards, 
Rahul 



KP Karl Posch September 16, 2019 12:48 PM UTC

Hello,

I now had the time to update the Blazor project to .Net Core 3.0 Preview 9 and along with int your UI FX to version. 17.2.0.50-beta. 

Unfortunately I can not confirm your fix for the problem described in this thread. In fact, it seems like applying a column template is not working at all in the current version.

I did try it again with the example I have provided below. I also tried one of the examples provided in your documentation, where a template is provided for one column so that it should display the ID of the order:
   
       
           
       
       
       
       
   

(rest omitted for clarity, exact copy of the example you provide in https://ej2.syncfusion.com/blazor/documentation/grid/templates/?no-cache=1 )

The ID column is empty instead:



Currently I can not use the grid further, because of the column templates still having troubles. 

Am I doing something wrong / can you reproduce the issue on your side ? If so, could you please provide a sample on how to display a list of objects with object each having additional values stored in a dictionary < string, object > ?

Best Regards,

Karl 





BI BigMac September 16, 2019 02:33 PM UTC

I ran into similar issues when using the Template inside a grid column although I wasn't using dictionary objects.  The columns would just show blank (at seemingly random times) for template columns where I was using the context object to display data. There was no issue with columns that used the GridColumn without the template. I tried to determine the cause but I couldn't figure it out since it seemed random (maybe async related?). I gave up trying to figure it out to submit a bug report.


RS Renjith Singh Rajendran Syncfusion Team September 17, 2019 08:44 AM UTC

Hi Karl/BigMac, 

Thanks for your updates. 

We have analyzed your query. We suspect that the problem is because of using older version script files. So we suggest you to ensure to use updated version(17.2.50) script and styles in your application. 

 
    <link rel='nofollow' href="https://cdn.syncfusion.com/ej2/17.2.50/material.css" rel="stylesheet" /> 

 

We have upgraded the sample to Preview9 and Syncfusion version 17.2.50. The template column shows fine with values, and its not empty. We are attaching the upgraded version of the sample from our previous update dated September 4, 2019. Please download the sample from the link below, 
 
And also we have analyzed the screenshot and tried to reproduce the problem by creating a sample by copying the codes from the attached documentation. But we could not reproduce the problem, we are attaching the sample which we have tried for your convenience. Please download the sample from the link below, 

If you are still facing difficulties in rendering a template column, we need more details to further proceed on this and provide you a solution as early as possible. 

  1. Share with us the sample which you have tried from your side.
  2. Share the exact scenario/proper replication procedure.
  3. Share a video demo explaining the problem you are facing.
  4. Share the details of script error if any occurred in the browser console.

The provided information will help us analyze the problem, and provide you a solution as early as possible. 

Regards, 
Renjith Singh Rajendran. 



KP Karl Posch September 23, 2019 10:05 AM UTC

Hello again,

thank you for your help so far. I updated the CSS and Script includes like you have shown in your last post. I have tried the samples I refered to in my previous post and they work fine now.

Hence I tried to apply a template to the orginial EjsGrid in my first post, which is working with an DynamicEntity type. Unfortunately I am still not able to apply a template there. Not even a simple one like outputting the same string value for every column, so that no object should be dereferenced in the end.

This is what i Tried:

Usage of the EjsGrid in a Custom DynamicEntityTable component:


How the DynamicEntityTable is used in an external comonent:

<DynamicEntityTable EntityDefinition="@ViewModel.EntityDefinition" Entities="@ViewModel.Entities">
</DynamicEntityTable>

I am trying to implement a MVVM approach for the Blazor app. The ViewModel is responsible for loading the Entities and their corresponding EntityDefinition.

As you can see in my provided sample, I am not even trying to access any properties / values of the object. The columns are created correctly, but the string output for each column is missing. This is what I get as end result:



The collection behind it does have 5 entries and the grid is also generating a row for each entry. No exception is displayed in the browser console directly after rendering. If I select one of the rows, the following exception is displayed in the browser console:

[2019-09-23T09:40:24.819Z] Error: System.MissingMethodException: Cannot create an instance of an interface.
   at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean wrapExceptions, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& hasNoDefaultCtor)
   at System.RuntimeType.CreateInstanceDefaultCtorSlow(Boolean publicOnly, Boolean wrapExceptions, Boolean fillCache)
   at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, Boolean wrapExceptions)
   at System.Activator.CreateInstance(Type type, Boolean nonPublic, Boolean wrapExceptions)
   at Syncfusion.EJ2.Blazor.BaseComponent.GetObject(Dictionary`2 Data, Type ModelType)
   at Syncfusion.EJ2.Blazor.BaseComponent.GetObject(Dictionary`2 Data, Type ModelType)
   at Syncfusion.EJ2.Blazor.Grids.GridColumn.BuildRenderTree(RenderTreeBuilder __builder)
   at Microsoft.AspNetCore.Components.ComponentBase.<.ctor>b__6_0(RenderTreeBuilder builder)
   at Microsoft.AspNetCore.Components.Rendering.ComponentState.RenderIntoBatch(RenderBatchBuilder batchBuilder, RenderFragment renderFragment)
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.RenderInExistingBatch(RenderQueueEntry renderQueueEntry)
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.ProcessRenderQueue()

To me it looks like that I am not doing anything different than in the sample with the Person-objects I provided (except creating the columns, which does work).

Below an excerpt of the DynamicEntity type in use (I excluded any methods)

Best Regards,

Karl Posch





RS Renjith Singh Rajendran Syncfusion Team September 24, 2019 01:29 PM UTC

Hi Karl, 
  
Thanks for your update. 
  
We have analyzed your codes and tried to reproduce the reported problem by preparing a sample with the same scenario by creating DynamicEntity class extending from DynamicObject. But we are not able to reproduce the reported problem, the Grid renders fine with the template column. We are attaching the sample which we have tried from our side for your convenience. Please download the sample from the link below, 
  
If you are still facing difficulties, kindly get back to us with the following details for better assistance. 
1.       Share with us the sample which you have tried from your side. 
2.       Or if possible, kindly reproduce the problem with the attached sample and share with us. 
  
The provided information will help us analyze the problem, and provide you a solution as early as possible. 
  
Regards, 
Renjith Singh Rajendran. 



KP Karl Posch October 2, 2019 10:00 AM UTC

Hello,

unfortunately, using the EjsGrid in combination with a collection of our DynamicEntity-type does still not work. I also think that the sample you have provided does not really reflect the same circumstances, in which I try to use your Grid. As you can see in the last pastebin I provided for the DynamicEntity-type, it does have a [DataContract] attribute, because it is used by a WCF service. Hence it is not possible to inherit this type from DynamicObject, as this base type is not serializable.

However, is it really possible to derive from this type, just because you want to access values from a Dictionary<string, object>? In the sample using the Person-model class it was possible to access the dictionary values, after your recent update. 

I tried to use a wrapper class so that the wrapper class would derive from DynamicObject and simly use a given DynamicObject-entity in the TryGetValue / TrySetValue methods. When I used objects of that wrapper class in your EjsGrid, I again run into the problem, that the underlying object is null inside the template.

This is how the wrapper class looks:

public class DynamicEntityWrapper : DynamicObject
    {

        public DynamicEntityWrapper() {}

        public DynamicEntityWrapper(DynamicEntity entity)
        {
            Entity = entity;
        }

    public class DynamicEntityWrapper : DynamicObject
    {

        public DynamicEntityWrapper() {}

        public DynamicEntityWrapper(DynamicEntity entity)
        {
            Entity = entity;
        }

        public DynamicEntity Entity { get; set; }

        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            DynamicEntityProperty dynamicProperty;
            var hasProperty = Entity.DynamicProperties.TryGetValue(binder.Name, out dynamicProperty);
            result = hasProperty ? dynamicProperty.Value : null;
            return hasProperty;
        }
        public override bool TrySetMember(SetMemberBinder binder, object value)
        {
            if(!Entity.DynamicProperties.ContainsKey(binder.Name)) return false;
            Entity.SetValue(binder.Name, value);
            return true;
        }
    }

This is how the Blazor component uses your EjsGrid and maps the IList<DynamicEntits> to an IList<DynamicEntityWrapper>, which it does get from the outside as parameter:

<div class="grid-view view-border">
    <h2>TestGrid</h2>
    <div class="container-fluid mb-2">
        @if (ViewDefinition != null)
        {
            <EjsGrid DataSource="@_entities" ModelType="@ModelType"
                     AllowSorting="@EnableSorting" AllowPaging="@EnablePaging"
                     AllowFiltering="@EnableFiltering">
                @if (RowTemplate != null)
                {
                    <GridTemplates>
                        <RowTemplate>
                            @RowTemplate
                        </RowTemplate>
                    </GridTemplates>
                }
                <GridColumns>
                    @foreach(var viewField in ViewDefinition.ViewFields.Where(viewField => viewField.Visible).OrderBy(viewField => viewField.ColumnIndex))
                    {
                        <GridColumn HeaderText="Test">
                            <Template>
                                @{
                                    var entityWrapper = context as DynamicEntityWrapper;
                                    if (entityWrapper.Entity == null)
                                    {
                                        <span>ENTITY NULL</span>
                                    }
                                    else
                                    {
                                        <span>@entityWrapper.Entity.GetValue(viewField.PropertyName)</span>
                                    }
                                }
                            </Template>
                        </GridColumn>
                    }
                </GridColumns>
            </EjsGrid>
        }
        else
        {
            //TODO [PK] Redirect to error page
            <p>Can not load data: no ViewDefinition found!</p>
        }
    </div>
    <div>
        @ChildContent
    </div>
</div>

@code {

    private IList<DynamicEntityWrapper> _entities = new List<DynamicEntityWrapper>();
    private DynamicEntityWrapper ModelType => new DynamicEntityWrapper();

    protected override async Task OnParametersSetAsyncInternal()
    {

    }

    [Parameter]
    public IList<DynamicEntity> Entities
    {
        get
        {
            return _entities.Select(wrapper => wrapper.Entity).ToList();
        }
        set
        {
            if(value != null)
            {
                _entities = value.Select(entity => new DynamicEntityWrapper(entity)).ToList();
            } else
            {
                _entities = null;
            }
            StateHasChanged();
        }
    }

    [Parameter]
    public RenderFragment ChildContent { get; set; }

    [Parameter]
    public bool EnablePaging { get; set; } = false;

    [Parameter]
    public bool EnableSorting { get; set; }

    [Parameter]
    public int PageSize { get; set; } = 20;

    [Parameter]
    public RenderFragment RowTemplate { get; set; }

This is the output I get in the browser:


From my understanding, the only thing I am trying to accomplish here, is to access values inside a dictionary. I also do not understand, why the DynamicEntity-object inside the wrapper is null when used inside the column template. When using DynamicEntity-type directly, it's the same output as before.

Could you please provide a working sample for me with the DynamicEntity class listed in my previous post? This is what the GetValue-method of the DynamicEntity does:

 public object GetValue(string name)
{
      return GetValueForce(name, false);
 }

public object GetValueForce(string name, bool ensure)
{
            if (DynamicProperties.ContainsKey(name))
            {
                return DynamicProperties[name].Value;
            }

            if (ensure)
            {
                throw new KeyNotFoundException($"Given property {name} couldn't be found on dynamic entity {this}");
            }

            return null;
}

DynamicProperties is a Dictionary<string, DynamicProperty>. DynamicProperty is just a simple wrapper around an object-value.

[DataContract]
    [Serializable]
    [KnownType(typeof(DynamicEntity))]
    public class DynamicEntityProperty:INotifyPropertyChanged
    {
        private object _value;

        [DataMember]
        public object Value
        {
            get => _value;
            set
            {
                if (Equals(value, _value))
                    return;
                _value = value;
                OnPropertyChanged();
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

Best Regards,

Karl Posch


RS Renjith Singh Rajendran Syncfusion Team October 3, 2019 01:22 PM UTC

Hi Karl, 

Thank for your update. 

We have created a new incident under your account. Kindly follow up the incident for future updates regarding this query. 

Regards, 
Renjith Singh Rajendran. 


Loader.
Live Chat Icon For mobile
Up arrow icon