Search code examples
c#wpfbindingdatagrid

Binding to DataGrid


I have two classes - Object and Parameters.

Public class Object
{
    public int ID { get; set; }
    public string Name { get; set; }
    ......
    public List<Parameters> Paramlist { get; set; } = new List<Parameters>();
}

Public class Parameters
{   
    public string parName { get; set; }
    public string Value { get; set; }   
}

There are about 40 types of Objects. Each Object type has multiple parameters, the common for all of them are listed in Object Class. However, each type also has it's own parameters. That's why I am using the List.

Now User can pick what kind of objects he wants to see in DataGrid. And then he can pick what kind of parameters he wants to see.

So only one DataGrid column is defined - ObjectName (Instance name). Others are added in runtime like this

 MainDataGrid.Columns.Add(new DataGridTextColumn
 {
     Header = _parameter,
     Binding = new System.Windows.Data.Binding(_parameter),
     //_parameter is string received from user by picking one of the parameters in another DataGrid

 });
  

And it works, but only for the parameters listed in Object class. Now I want to Bind also the other parameters. Basically go through each instance in DataGrid and if the instance has the parameter in the List, Bind the value from the list to a new column.

I don't necessarily need it to be List, that was the first idea i worked with. Obviously not a very good one.

Thanks for any suggestions.


Solution

  • After some struggle understanding your issue, I believe you are looking for Indexers

    Here the documentation:

    https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/indexers/

    Extend your Object class with an indexer

    public class Object
    {
        public int ID { get; set; }
        public string Name { get; set; }
    
        public string this[string propertyName]
        {
            get
            {
                var parameterByName = Paramlist.FirstOrDefault(x => x.Name == propertyName);
                return parameterByName?.Value;
            }
            set
            {
                var parameterByName = Paramlist.FirstOrDefault(x => x.Name == propertyName);
                if (parameterByName == null)
                    Paramlist.Add(new Parameters() { Name = propertyName, Value = value });
                else
                    parameterByName.Value = value;
            }
        }
    
        public List<Parameters> Paramlist { get; set; } = new List<Parameters>();
    }
    

    By doing this you can create a Binding with the indexer syntax [PropertyName].

    eg.

    new System.Windows.Data.Binding("[MyProperty]")
    

    Here a working sample:

    MainWindow.xaml

    <Window x:Class="WpfApp59.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            mc:Ignorable="d"
            Title="MainWindow"
            Height="450"
            Width="800"
            DataContext="{Binding RelativeSource={RelativeSource Self}}">
        <Grid>
            <DataGrid ItemsSource="{Binding MyItems}"
                      Name="MainDataGrid"
                      AutoGenerateColumns="False">
    
                <!-- if you want to define the columns in xaml and not code behind -->
                <!--<DataGrid.Columns>
                    <DataGridTextColumn Binding="{Binding MySharedProperty}" />
                    <DataGridTextColumn Binding="{Binding MyFooProperty}" />
                    <DataGridTextColumn Binding="{Binding MyBarProperty}" />
                    <DataGridTextColumn Binding="{Binding [MyMagic1]}" />
                    <DataGridTextColumn Binding="{Binding [MyMagic2]}" />
                    <DataGridTextColumn Binding="{Binding [MyMagic3]}" />
                </DataGrid.Columns>-->
            </DataGrid>
        </Grid>
    </Window>
    

    MainWindow.xaml.cs

    public partial class MainWindow : Window
    {
        public IEnumerable<object> MyItems { get; set; } = new object[]
        {
            new Foo(){
                MySharedProperty = "I'm a Foo object.", 
                MyFooProperty = "Foo Property",
                ParamList = new List<Parameters>()
                {
                    new Parameters(){Name = "MyMagic1", Value = "Foo Magic Value 1"},
                    //new (){Name = "MyMagic2", Value = "Foo Magic Value 2"},
                    new Parameters(){Name = "MyMagic3", Value = "Foo Magic Value 3"}
                }
            }, 
            new Bar(){
                MySharedProperty = "I'm a Bar object.", 
                MyBarProperty = "Bar Property",
                ParamList = new List<Parameters>()
                {
                    new Parameters(){Name = "MyMagic1", Value = "Bar Magic Value 1"},
                    new Parameters(){Name = "MyMagic2", Value = "Bar Magic Value 2"},
                    //new (){Name = "MyMagic3", Value = "Foo Magic Value 3"}
                }
            }
        };
    
        public MainWindow()
        {
            InitializeComponent();
    
            string[] parameters = new string[] {
                "MySharedProperty", 
                "MyFooProperty", 
                "MyBarProperty",
                "[MyMagic1]",
                "[MyMagic2]",
                "[MyMagic3]"
            };
    
            foreach (var parameter in parameters)
            {
                MainDataGrid.Columns.Add(new DataGridTextColumn
                {
                    Header = parameter,
                    Binding = new System.Windows.Data.Binding(parameter),
                });
            }
        }
    }
    

    SharedObject.cs

    public class SharedObject
    {
        public string MySharedProperty { get; set; }
    
        public string this[string propertyName]
        {
            get
            {
                var parameterByName = ParamList.FirstOrDefault(x => x.Name == propertyName);
                return parameterByName?.Value;
            }
            set
            {
                var parameterByName = ParamList.FirstOrDefault(x => x.Name == propertyName);
                if (parameterByName == null)
                    ParamList.Add(new Parameters() { Name = propertyName, Value = value });
                else
                    parameterByName.Value = value;
            }
        }
    
        public List<Parameters> ParamList { get; set; }
    }
    

    Foo.cs

    public class Foo : SharedObject
    {
        public string MyFooProperty { get; set; }
    }
    

    Bar.cs

    public class Bar : SharedObject
    {
        public string MyBarProperty { get; set; }
    }
    

    Parameters.cs

    public class Parameters
    {
        public string Name { get; set; }
        public string Value { get; set; }
    }
    

    Result of the sample should be:

    enter image description here