So currently I have a DataGrid that looks like this: Current DataGridView
The goal behind this is to create an import utility. The data received in CSV format isn't always structured the same way. The columns change order, sometimes they only provide partial data.
I'd like for the user to be able to select where each column is directed. I'm running into a few problems and I was hoping someone more experienced could direct me.
First, the type of the data entered is still restricted. So for example, if column 1 is an integer, then it won't allow for text input. I was planning on writing an event handler for when the headers ComboBox changed to change the BindingExpression. but realistically this just needs to be a typeless column. Which would be entered into the actual table based on the comboBox selection afterwards.
I'm also unsure how to identify/get at the ComboBox from the ViewModel when it's generated this way.
xaml
<DataGrid x:Name="ImportTable"
ItemsSource="{Binding displayTable}"
AutoGeneratingColumn="OnAutoGeneratingColumn"
AutoGenerateColumns="True"
CanUserAddRows="True"
CanUserDeleteRows="True"
EnableColumnVirtualization="True"
EnableRowVirtualization="True"
MaxWidth="1300"
MaxHeight="600"
/>
xaml.cs
//i keeps track of the column index, temporary solution to preset columns
private int i;
private void OnAutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
var cb = new ComboBox();
cb.ItemsSource = (DataContext as EnterValueDialogViewModel).displayTable.Columns;
cb.DisplayMemberPath = "ColumnName";
cb.SelectedValue = e.PropertyName.ToString();
cb.SelectedIndex = i;
e.Column.Header = cb;
i++;
}
Here's a rough sketch of the basic wiring. We've got a class called
ColumnHeaderViewmodel
that represents the header for one column. TheMainViewModel
has a collection of those as well as aDataTable
property calledData
. ThatDataTable
is one relatively tolerable way to display arbitrary, known-only-at-runtime CSV in aDataGrid
. Another way is anObservableCollection<ExpandoObject>
, with some extra code to generate the columns. We can go into that if need be.It's a bad idea to create WPF UI in C#. Anybody who's experienced with WPF avoids that kind of thing if he possibly can.
We'll store the CSV in a separate structure, perhaps
List<List<String>>
or something, and every time the column headers change, we'll repopulate theDataTable
from that collection. That's your problem, I'm not addressing it. See the "TODO" comments.This code is a complete self-contained example that lets you rename columns from header comboboxes. You can add other stuff (e.g. datatype, or an include/exclude flag) to
ColumnHeaderViewModel
and to the header template.First, we'll illustrate how to put comboboxes in DataGrid column headers. Don't do it in C#.
Second, in the codebehind file for the above XAML (maybe your MainWindow, maybe a UserControl), we'll wire up the ColumnHeaderViewModels; they're in
ViewModel.Columns
:MainViewModel:
ColumnHeaderViewModel