I'm trying to create a datagrid which has a entries which have properties coming from a json. The problem is that a lot of the properties should be dynamically generated based on the information that is in the json.
The first thing I tried was to make a very long list of all possible properties with their own getters & seters. But it's a very long list and it felt like there should be an automated solution for this problem. This is included at the end of Datagrid Entry View Model. So I am able to bind to Number when:
Number = obj.NUMBER;
After that I researched into dynamic types and expandoObjects. I learned that apperently it's not possible to bind WPF to an expandoObject's expanded properties. So I cannot bind to expando.Number
expando.Number = obj.NUMBER
I also tried to follow this example in which helper classes are created to help with the binding, but I can't seem to get it to work. When I run my solution I get an error saying that the property "Numberz" doesn't exist. So I cannot bind to Numberz:
AddProperty("Numberz", typeof(string));
SetPropertyValue("Numberz", obj.NUMBER);
At moment I'm out of ideas, so if anybody here could help, I would be very grateful. Maybe a few last notes. I'm not a very experienced programmer and I'm trying to work through an MVVM-pattern.
Datagrid entry view model
public class DatagridEntryViewModel : ICustomTypeProvider, INotifyPropertyChanged { #region Fields
/// <summary>
/// Custom Type provider implementation - delegated through static methods.
/// </summary>
private readonly CustomTypeHelper<DatagridEntryViewModel> _helper = new CustomTypeHelper<DatagridEntryViewModel>();
#endregion
#region Constructor
public DatagridEntryViewModel(ExitCoil model)
{
_helper.PropertyChanged += (s, e) => PropertyChanged(this, e);
dynamic Json = JObject.Parse(model.JsonCoilData);
//CreationDatePost = Json.CREATION_DATE_S_POST;
////Number = Json.NUMBER;
//CreationDatePost = Json.CREATION_DATE_S_POST;
////LeverageOrder = Json.LEVERAGE_ORDER;
//Client = Json.CLIENT;
//Skinned = Json.SKINNED;
dynamic expando = new ExpandoObject();
dynamic obj = JsonConvert.DeserializeObject<ExpandoObject>(Json.ToString());
//AddProperty("Numberz", typeof(string));
//SetPropertyValue("Numberz", obj.NUMBER);
//expando.AddItem("Number");
//expando[0] = obj.NUMBER;
//Number = expando.Number;
Model = model;
//var settings = new JsonSerializerSettings();
//settings.Converters.Add(new Models.DynamicJsonConverter());
//var serializer = JsonSerializer.Create(settings);
//JsonReader reader = new JsonTextReader(new StringReader(JsonString));
//var Data = serializer.Deserialize<DynamicObject>(reader);
}
#endregion
#region Model & proxy
private ExitCoil _model;
public ExitCoil Model
{
set { _model = value; }
}
#endregion
#region Public Methods
// Methods to support dynamic properties.
public static void AddProperty(string name)
{
CustomTypeHelper<DatagridEntryViewModel>.AddProperty(name);
}
public static void AddProperty(string name, Type propertyType)
{
CustomTypeHelper<DatagridEntryViewModel>.AddProperty(name, propertyType);
}
public static void AddProperty(string name, Type propertyType, List<Attribute> attributes)
{
CustomTypeHelper<DatagridEntryViewModel>.AddProperty(name, propertyType, attributes);
}
public void SetPropertyValue(string propertyName, object value)
{
_helper.SetPropertyValue(propertyName, value);
}
public object GetPropertyValue(string propertyName)
{
return _helper.GetPropertyValue(propertyName);
}
public PropertyInfo[] GetProperties()
{
return _helper.GetProperties();
}
Type ICustomTypeProvider.GetCustomType()
{
return _helper.GetCustomType();
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private void RaisePropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
#region Properties
//public string Number { get; private set; }
//public string CreationDatePost { get; private set; }
//public string LeverageOrder { get; private set; }
public string Client { get; private set; }
//public int OrderZnTop { get; private set; }
//public int OrderZnBottom { get; private set; }
//public string OrderAspect { get; private set; }
//public string OderSideTrimming { get; private set; }
//public string OrderPassivation { get; private set; }
//public string OrderOilType { get; private set; }
//public string OrderOilQuantity { get; private set; }
#endregion
}
Datagrid view model
public class DatagridViewModel : MainViewModelBase
{
#region Singleton
public static DatagridViewModel Instance = new DatagridViewModel();
#endregion
#region Fields
private ObservableCollection<DatagridEntryViewModel> _coilEntries = new ObservableCollection<DatagridEntryViewModel>();
private readonly IViewManager _viewManager;
private readonly IDockManager _dockManager;
#endregion
#region Properties
public ObservableCollection<DatagridEntryViewModel> CoilEntries
{
get { return _coilEntries; }
set
{
_coilEntries = value;
RaisePropertyChanged(() => CoilEntries);
}
}
public ProductionExitCoilReport Report { get; set; }
#endregion
#region Constructor
public DatagridViewModel()
{
_viewManager = Globals.Container.Resolve<IViewManager>();
_dockManager = Globals.Container.Resolve<IDockManager>();
getReport();
foreach (var Coil in Report.Coils)
{
CoilEntries.Add(new DatagridEntryViewModel(Coil));
}
}
#endregion
#region Methods
public void getReport()
{
var proxy = new Proxy<IReportService>();
proxy.Open();
var LijnId = new LijnIdentificatie { Department = "HDG", Firm = "LIE", LineNumber = "05" };
var Periode = new Period { FromDate = new DateTime(2017 - 11 - 10), FromShift = 1, ToDate = new DateTime(2017 - 11 - 10), ToShift = 1 };
var request = new ProductionReportRequest() { LijnIdentificatie = LijnId, Period = Periode };
Report = proxy.Service.GetProductionExitCoilReport(request);
}
#endregion
}
Datagrid XAML
<DataGrid x:Class="Promo.Presentation.Views.CoilGrid"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/marukp-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Promo.Presentation.Views"
xmlns:components="clr-namespace:Promo.Presentation.Components"
xmlns:Data="clr-namespace:Promo.Presentation.ViewModels"
AutoGenerateColumns="False"
GridLinesVisibility="none"
Background="White"
Height="Auto"
Width="Auto"
MinWidth="500"
MinHeight="500"
DataContext="{x:Static Data:DatagridViewModel.Instance}"
ItemsSource="{Binding CoilEntries}"
IsReadOnly="True"
HeadersVisibility="Column"
Padding="10"
>
<DataGrid.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../Styles/Colors.xaml"/>
<ResourceDictionary Source="../Styles/Datagrid.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Numberz}" Header="Rolnummer" MaxWidth="125"/>
<DataGridTextColumn Binding="{Binding CreationDatePost}" Header="Post" MaxWidth="200"/>
<DataGridTextColumn Binding="{Binding LeverageOrder}" Header="Leverage order" MaxWidth="200"/>
<DataGridTextColumn Binding="{Binding Client}" Header="Client" MaxWidth="400"/>
<DataGridTextColumn Binding="{Binding OrderZnTop}" Header="Order zinc top" MaxWidth="200"/>
<DataGridTextColumn Binding="{Binding OrderZnBottom}" Header="Order zinc bottom" MaxWidth="200"/>
<DataGridTextColumn Binding="{Binding OrderAspect}" Header="Order aspect" MaxWidth="125"/>
<DataGridCheckBoxColumn Binding="{Binding OrderSideTrimming, Converter={local:StringToBoolConverter}}" Header="Order Side Trimming" MaxWidth="200"/>
<DataGridTextColumn Binding="{Binding OrderPassivation}" Header="Order Passivation" MaxWidth="200"/>
<DataGridCheckBoxColumn Binding="{Binding Skinned, Converter={local:StringToBoolConverter}}" Header="Skinned" MaxWidth="200"/>
</DataGrid.Columns>
</DataGrid>
Part of the Json
{"NUMBER":"G571015110 ","CREATION_DATE_S_POST":"2017-05-11T00:00:00""LEVERAGE_ORDER":"FD72BIGA5W/8","CLIENT":"ARCELORMITTAL BELGIUM SA "}