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