I am building a WPF MVVM application.
What I have:
I have a DataTable
, binded to a DataGrid
as such:
<DataGrid
Name="Map"
AutoGenerateColumns="True"
AutoGeneratingColumn="Map_AutoGeneratingColumn"
IsReadOnly="True"
ItemsSource="{Binding MapDataTable}" />
Here is how I am creating the data table in the ViewModel
:
ObservableCollection<ObservableCollection<MapModel>> MapDataList { get; set; }
private void CreateDataTable(IEnumerable<MapModel> mapDataItems)
{
MapDataTable.Clear();
DataTable dataTable = new DataTable("MapDataTable");
dataTable.Columns.Add("First", typeof(string));
dataTable.Columns.Add("Second", typeof(string)); //typeof might need to be changed to ObservableCollection<SomeModel> (still works) or ComboBox
var mapData = new ObservableCollection<MapModel>();
foreach (var item in mapDataItems)
{
mapData.Add(item);
}
MapDataList.Add(mapData);
foreach (MapModel item in mapDataItems)
{
DataRow dataRow = dataTable.NewRow();
dataRow[0] = item.Name;
dataRow[1] = item.SomeValues; //mistake could be here
dataTable.Rows.Add(dataRow);
}
MapDataTable = dataTable;
}
MapModel.cs:
public class MapModel
{
public string Name { get; set; }
public ObservableCollection<SomeModel> SomeValues { get; set; } = new ObservableCollection<SomeModel>
{
new SomeModel(),
new SomeModel()
};
}
SomeModel.cs:
public class SomeModel
{
public string Name { get; set; }
public double Value { get; set; }
public SomeModel()
{
Name = "test";
Value = 0;
}
}
Map_AutoGeneratingColumn in the xaml.cs:
if (e.PropertyName == "Second")
{
var templateColumn = new DataGridTemplateColumn
{
Header = e.PropertyName,
CellTemplate = (sender as FrameworkElement).FindResource("SecondCellTemplate") as DataTemplate,
CellEditingTemplate = (sender as FrameworkElement).FindResource("SecondCellEditingTemplate") as DataTemplate
};
e.Column = templateColumn;
}
In the View:
<Grid.Resources>
<DataTemplate x:Key="SecondCellTemplate">
<TextBlock Text="{Binding Path=???, Mode=OneWay}" />
</DataTemplate>
<DataTemplate x:Key="SecondCellEditingTemplate">
<ComboBox
DisplayMemberPath="Name"
ItemsSource="{Binding Path=SomeValues, Mode=OneWay}" //wrong binding
SelectedValue="{Binding Path=???, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
SelectedValuePath="Name" />
</DataTemplate>
</Grid.Resources>
What I want to achieve:
I want the SomeValues
' names to be displayed in the ComboBox
of the DataGridTemplateColumn
.
How do I achieve this?
EDIT:
From this comment (https://stackoverflow.com/a/35212223/17198402) I understand how to bind SomeValues
IF the columns were hardcoded and not autogenerated, but I still can't wrap my head around how to do it when they are autogenerated. Setting the ItemsSource
in the code-behind is still a mystery to me. As far as I understand, DataGridTemplateColumn
doesn't inherit the DataContext
, unlike DataGridTextColumn
.
EDIT 2:
I was able to bind to a property in my ViewModel
this way:
ViewModel.cs
public ObservableCollection<SomeModel> SomeValues { get; set; } = new ObservableCollection<SomeModel>
{
new SomeModel(),
new SomeModel()
};
xaml:
<Grid.Resources>
<DataTemplate x:Key="SecondColumnTemplate" DataType="DataGridCell">
<ComboBox
DisplayMemberPath="Name"
ItemsSource="{Binding Path=DataContext.SomeValues, RelativeSource={RelativeSource AncestorType=Page}}" />
</DataTemplate>
</Grid.Resources>
AutoGeneratingColumn:
var templateColumn = new DataGridTemplateColumn
{
Header = e.PropertyName,
CellTemplate = (sender as FrameworkElement).FindResource("SecondColumnTemplate") as DataTemplate
};
e.Column = templateColumn;
This successfully binds the new property in the ViewModel, but of course that's not what I want. How do I bind to the current item.SomeValues
?