Developing a WPF
app using MVVMLight
.
I'm trying to bind each DataGridColumn
of a DataGrid
(with AutoGenerateColumns
set to False
) to one ObservableCollection<string>
per column. I've already asked something similar and received a very good answer but the problem with that approach is that items get added in the DataGrid
one row at a time. That approach also introduces a new Model
class which makes it a problem for TwoWay
binding with the actual Model
class I need to keep in sync with my View
.
My question is this: Assuming that I have several ObservableCollection<string>
of the exact same count/length, is it possible to bind one ObservableCollection<string>
per column? My approach so far has been this:
ObservableCollection<ObservableCollection<string>>
(let's name it GridColumns
) property on my ViewModel
containing each ObservableCollections<string>
I needItemsSource
of my DataGrid
to GridColumns
DataGridColumn
to each ObservableCollection<string>
in GridColumns
I can't seem to get it to work though. Am I totally off with this approach?
EDIT:
Here is what I came up with:
1) Created a Model
class which exposes ObservableCollection
properties
public class AttributeListItems : ObservableObject
{
private ObservableCollection<string> category;
public ObservableCollection<string> Category
{
get { return category; }
set
{
if (category == value)
{
return;
}
category = value;
RaisePropertyChanged(() => Category);
}
}
private ObservableCollection<string> fileValue;
public ObservableCollection<string> FileValue
{
get { return fileValue; }
set
{
if (fileValue == value)
{
return;
}
fileValue = value;
RaisePropertyChanged(() => FileValue);
}
}
}
2) Created a property of ObservableCollection<AttributeListItems>
on my ViewModel
:
private ObservableCollection<AttributeListItems> gridItems;
public ObservableCollection<AttributeListItems> GridItems
{
get { return gridItems; }
set
{
if (gridItems == value)
{ return; }
gridItems = value;
RaisePropertyChanged(() => GridItems);
}
}
3) On the setter
of my SelectedAttribute
property of my ViewModel
(which is when I want GridItems
to be repopulated) I added this:
gridItems.Clear();
gridItems.Add(new AttributeListItems {
Category = selectedAttribute.Categories,
FileValue = selectedAttribute.FileValues }
);
RaisePropertyChanged(() => GridItems);
4) And on my View
I set the ItemsSource
of the DataGrid
to GridItems
and the binding of it's column to Category
, as such:
<DataGrid Grid.Row="0" Grid.ColumnSpan="2" Margin="5" AutoGenerateColumns="False" ItemsSource="{Binding GridItems}" EnableColumnVirtualization="True" CanUserReorderColumns="False" CanUserSortColumns="False" VerticalScrollBarVisibility="Visible" >
<DataGrid.Columns>
<DataGridTextColumn Header="categories" Width="auto" Binding="{Binding Category}" />
<!--<DataGridTextColumn Header="file values" Width="auto" Binding="{Binding FileValue}" />-->
</DataGrid.Columns>
</DataGrid>
When I run this, the DataGrid
only shows one row in the column, it's text being "(Collection)"
. I tried changing the binding of the column from Category
to Category/
, which partially works: it only shows the first value of the Category
collection instead of all of them, which is where I'm stuck at the moment.
Firstly, you need a
class RowItem
{
bool IsChecked;
string Category;
string FileValue;
}
Then you populate a Collection of RowItem
s where ever you need it, by something like
GridData = new ObservableCollection<RowItem>();
And finally in the XAML,
<DataGrid Grid.Row="0" Grid.ColumnSpan="2" Margin="5" AutoGenerateColumns="False" ItemsSource="{Binding GridData}" EnableColumnVirtualization="True" CanUserReorderColumns="False" CanUserSortColumns="False" VerticalScrollBarVisibility="Visible" >
<DataGrid.Columns>
<DataGridCheckBoxColumn Header="Is Checked" Width="auto" IsChecked="{Binding IsChecked}" />
<DataGridTextColumn Header="Categories" Width="auto" Binding="{Binding Category}" />
<DataGridTextColumn Header="File values" Width="auto" Binding="{Binding FileValue}" />
</DataGrid.Columns>
</DataGrid>
Also, it seems like you have selectedAttribute.Categories
and selectedAttribute.FileValues
collections as the data source.
Assuming that they have the same length the GridData
can be populated by:
var rowItems = new List<RowItem>();
for( int i = 0; i < selectedAttribute.Categories.Count; i++ )
{
var row = new RowItem
{
Category = selectedAttribute.Categories[i],
FileValues = selectedAttribute.FileValues[i],
};
rowItems.Add(row);
}
GridData = new ObservableCollection<RowItem>(rowItems);