Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I automatically bind a string array to a WPF DataGrid?

I have a DataGrid inside of a UserControl. It looks like this:

<UserControl x:Class="ExternalDataSourceComparison.ImportedInfoGrid"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300"
         Height="Auto" Width="Auto">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition/>
    </Grid.RowDefinitions>
    <DataGrid Name="_dataGrid" Grid.Row="0">
        <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding Path[0].Length}"/>
        </DataGrid.Columns>
    </DataGrid>
</Grid>

I have the UserControl in my MainWindow that looks like this:

<Window x:Class="ExternalDataSourceComparison.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:ExternalDataSourceComparison"
    Title="MainWindow" Height="350" Width="525" WindowState="Maximized">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <local:ImportedInfoGrid x:Name="ExternalData" Grid.Row="0"/>
    <StackPanel Height="36px" Orientation="Horizontal" Grid.Row="1">
        <Button Name="_import" Content="Import Data" Margin="5" Padding="5, 2" Click="Import_Click"/>
        <Button Name="_compare" Content="Compare" Margin="5" Padding="5, 2" Click="Compare_Click"/>
        <Button Name="_cancel" Content="Cancel" Margin="5" Padding="5, 2" Click="Cancel_Click"/>            
    </StackPanel>
</Grid>

In my code behind for the window using the method fs.CSVToStringArray, I open up a CSV file and parse out the contents to a string[][] the outer array represents the rows and the inner array are all of the columns so string[0][3] would be row 1 column 4.

In my code behind I just set ItemsSource equal to the array of arrays as shown below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Data;

namespace ExternalDataSourceComparison
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        FileStuff fs = new FileStuff();
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Import_Click(object sender, RoutedEventArgs e)
        {
            string[][] array = fs.CSVToStringArray();
            this.ExternalData._dataGrid.ItemsSource = array;
        }

        private void Cancel_Click(object sender, RoutedEventArgs e)
        {

        }

        private void Compare_Click(object sender, RoutedEventArgs e)
        {

        }
    }
}

The output is not what I expected at all though. I think it showing the attributes of the object instead of the actual content. Is there a way to automatically generate rows and columns or will I have to write the code to create the columns and build the rows? I thought with a DataGrid you could bind something like a string[][] or a List<string[]> to the ItemsSource and it would just generated columns. It is currently automatically generating columns, it just isn't filling them with the contents of the string[][].

like image 684
Adam Avatar asked Apr 07 '14 20:04

Adam


1 Answers

DataGrid's auto-generate columns feature isn't quite suitable for displaying jagged array data. It is better suited for single, one-dimentional collection where each row in DataGrid represent single item in collection, and each column represent different property of corresponding item.

And unless the item in ItemsSource is a model that is ready for display, you shouldn't rely on auto-generate columns feature (it will display column for all properties, including those properties not meant to be displayed). Another issue when trying to automagically bind DataGrid to array is, DataGrid doesn't have information on how it should name the column.

In the end, I think you better define DataGrid columns somehow, instead of letting DataGrid it self generate the columns. Either define it from XAML, for example, assuming you always have two "columns" in the array :

<DataGrid Name="_dataGrid" Grid.Row="0" AutoGenerateColumns="False">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Column 1" Binding="{Binding [0]}"/>
        <DataGridTextColumn Header="Column 2" Binding="{Binding [1]}"/>
    </DataGrid.Columns>
</DataGrid>

Or define the columns from code, in case you have dynamic number of columns, for example :

string[][] array = fs.CSVToStringArray();
for (int i = 0; i < array[0].Length; i++)
{
    var col = new DataGridTextColumn();
    col.Header = "Column " + i;
    col.Binding = new Binding(string.Format("[{0}]", i));
    _dataGrid.Columns.Add(col);
}
this.ExternalData._dataGrid.ItemsSource = array;
like image 183
har07 Avatar answered Oct 01 '22 03:10

har07