4

My project is a C# application to import data from an excel sheet to the database and prompt the user to map them manually.

I need to create two rows:

  1. The first row is a DataGridTextColumn where the excel's headers fit to.
  2. The second row is a DataGridComboBoxColumn having the column_name of the data base

Each one of the DataGridTextColumn have a combo box.

But I'm facing a problem where I'm not able to make the DataGridComboBoxColumn work, every time I launch the application, the first row is working normally but the second row is empty

code :

foreach (DataRow row in dt.Rows)
{
     DataGridTextColumn dgtc = new DataGridTextColumn();
     dgtc.MinWidth = 100;
     dgtc.CanUserSort = false;
     dgtc.Header = row["Column_name"].ToString();
     dg.Columns.Add(dgt);
     DataGridComboBoxColumn dgcbc = new DataGridComboBoxColumn();
     dgcbc.ItemsSource = columnList;
     dgcbc.MinWidth = 100;
     dg2.Columns.Add(dgcbc);
}

xaml :

 <DataGrid x:Name="dg" HorizontalAlignment="Left" Height="29" Margin="11,72,0,0" VerticalAlignment="Top" Width="579"/>
 <DataGrid x:Name="dg2" HorizontalAlignment="Left" Height="30" Margin="11,106,0,0" VerticalAlignment="Top" Width="579"/>

live view:

screenshot

the code is working but the combo boxes are always showing empty fields.

any help on why DataGridComboBoxColumn is not working for me ?

Salwa Najm
  • 47
  • 5
  • What and where is `columnList` coming from? I'm guessing that is either `null` or empty... – Chris Badman Oct 17 '14 at 12:01
  • SqlConnection conn = new SqlConnection("server=***;database=***;Integrated Security = true"); string[] restrictions = new string[4] { null, null, "orders", null }; conn.Open(); var columnList = conn.GetSchema("Columns", restrictions).AsEnumerable().Select(s => s.Field("Column_Name")).ToList(); That was enough to make sure that columnList is not null and it has 4 Strings, i even tested it.. – Salwa Najm Oct 17 '14 at 16:55

1 Answers1

1

There are 2 issues you might be referring to. First one is that setting dgcbc.ItemsSource = columnList is not enough to make ComboBox display list of items to choose from.

Depending on the type of columnList you need to set DisplayMemberPath and SelectedValuePath properties, for example:

var columnList = new Dictionary<string, string>
{
    { "123", "test 123" },
    { "aaa", "test aaa" },
    { "qwe", "test qwe" }
};

dgcbc.ItemsSource = columnList;
dgcbc.DisplayMemberPath = "Key";
dgcbc.SelectedValuePath = "Value";

Another issue is binding of the column to the ItemsSource which is set on your DataGrid object(s).

dg2.ItemsSource = dt;
dgcbc.TextBinding = new Binding(string.Format("[{0}]", "Column_Name");

You might also wonder how to display text in DataGridTextColumn:

dgtc.Binding = new Binding(string.Format("[{0}]", "Column_Name");

I am unsure if this is what you want to achieve for column mapping, probably you would like to modify a header template of the grid and present the grid data as text below. To do this use DataGridTemplateColumn DataGridTextColumn column with both header Label and ComboBox in it's header. hope it helps.

Edit:

I prepared a quick and dirty code only solution.

XAML:

<DataGrid x:Name="dg" Grid.Row="0" AutoGenerateColumns="False"/>

Code behind:

        // data is a rough equivalent of DataTable being imported
        var data = new List<Dictionary<string, string>>
        {
            new Dictionary<string, string> { { "column1", "asd asfs af" }, { "column2", "45dfdsf d6" }, { "column3", "7hgj  gh89" } },
            new Dictionary<string, string> { { "column1", "aaasdfda" }, { "column2", "45sdfdsf 6" }, { "column3", "78gh jghj9" } },
            new Dictionary<string, string> { { "column1", "s dfds fds f" }, { "column2", "4dsf dsf 56" }, { "column3", "78gh jgh j9" } },
        };

        // a list of columns to map to
        var importToColumns = new List<string>
        {
            "123",
            "aaa",
            "qwe",
            "456",
            "bbb"
        };

        importMappings = new Dictionary<string, int>();
        foreach(var column in data[0])
        {
            importMappings.Add(column.Key, -1);
        }

        foreach(var r in importMappings)
        {
            var dgtc = new DataGridTextColumn();
            dgtc.Binding = new Binding(string.Format("[{0}]", r.Key));
            var sp = new StackPanel();
            dgtc.Header = sp;
            sp.Children.Add(new Label { Content = r.Key });
            var combo = new ComboBox();
            sp.Children.Add(combo);
            combo.ItemsSource = importToColumns;
            var selectedBinding = new Binding(string.Format("[{0}]", r.Key));
            selectedBinding.Source = importMappings;
            combo.SetBinding(Selector.SelectedIndexProperty, selectedBinding);
            dgtc.MinWidth = 100;
            dgtc.CanUserSort = false;
            dg.Columns.Add(dgtc);
        }

        dg.ItemsSource = data;
    }

    private Dictionary<string, int> importMappings;

After selection has been approved, importMappings will contain a list of mappings of columns - for each import file column it will contain an index of element in importToColumns list or -1 if no elements were selected.

too
  • 3,009
  • 4
  • 37
  • 51
  • now that thanks to you i know my question.. how to implement a DataGridTemplateColumn column with both header Label and ComboBox in it. unfortunately it's been 3 days of researches and yet nothing.. – Salwa Najm Oct 17 '14 at 19:05
  • I did some configuration to the code but thanks it helped me a lot. – Salwa Najm Oct 20 '14 at 15:56