Search code examples
c#xamlbindingdatagridavaloniaui

How to bind "DataGrid.Items" with ObservableCollection<SomeType[]>?


I am looking for way to bind Avalonia DataGrid.Items with ObservableCollection<SomeType[]> collection. So, row is array of SomeType[] where every element is value for DataGrid cell. Is it possible? Now it binding fields of class Array instead of binding elements and I know, it is a usual way. But I need to do it dynamically when I don't know how many columns it can take. Like DataTable.DefaultView and DataGrid in .NET.

In my XAML it look like this:

<DataGrid AutoGenerateColumns="True" Items="{Binding Rows}"/>

where Rows is ObservableCollection<string[]> Rows { get; set; } inside my view model.


Solution

  • In short: You can't do that via AutoGenerateColumns.

    Let's suppose I've this simplified UI:

    <Window x:Class="_Test.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="450" Width="800">
        <Grid>
            <DataGrid x:Name="Grid"></DataGrid>
        </Grid>
    </Window>
    

    Then If I specify the Grid's ItemsSource like this:

    public MainWindow()
    {
        InitializeComponent();
        var dataSource = new ObservableCollection<string[]>
        {
            new []{ "A", "B", "C"},
            new []{ "C", "B", "A"},
        };
        Grid.ItemsSource = dataSource;
    }
    

    Then I would see the following result:

    Arrays' properties are showed

    So, it shows the arrays' properties instead of their content.


    In order to list their content you need to manually add the columns to the Grid:

    foreach (var idx in dataSource[0].Select((value, index) => index))
    {
        Grid.Columns.Add(new DataGridTextColumn { Header = $"{idx + 1}. column", Binding = new Binding($"[{idx}]") });
    }
    

    Let's put everything together:

    public MainWindow()
    {
        InitializeComponent();
        var dataSource = new ObservableCollection<string[]>
        {
            new []{ "A", "B", "C"},
            new []{ "C", "B", "A"},
        };
    
        foreach (var idx in dataSource[0].Select((value, index) => index))
        {
            Grid.Columns.Add(new DataGridTextColumn { Header = $"{idx + 1}. column", Binding = new Binding($"[{idx}]") });
        }
    
        Grid.AutoGenerateColumns = false;
        Grid.ItemsSource = dataSource;
    }
    

    and the result will be:
    Arrays' content are showed

    Credit goes to har07