I've the following classes in a WPF project
public class part
{
public string number { get; set; }
public string name { get; set; }
public List<department> departments { get; set; }
}
public class department
{
public string name { get; set; }
public double hours { get; set; }
}
Each part contains a list of hours for different departments. What i'm trying to achieve is to view this in a WPF listview. My problem is that i'm not finding a good example on how i could bind the a list of objects to a listviewitem. I had a similiar case in a windows forms app. There i iterated through the objects in the list and created subitems by code. While this would also possible here by creating gridviewcolumns in code i do believe that it should also be achievable via binding or am i mistaken?
Example:
public void Test()
{
List<part> list_parts = new List<part>();
List<department> list_departments = new List<department>();
department d = new department();
d.name = "Sawing";
d.hours = 0.3;
list_departments.Add(d);
d = new department();
d.name = "Miling";
d.hours = 12.3;
list_departments.Add(d);
part Test = new part();
Test.name = "Block";
Test.number = "123";
Test.departments = list_departments;
list_parts.Add(Test);
d = new department();
d.name = "Sawing";
d.hours = 1.2;
list_departments.Add(d);
d = new department();
d.name = "Turning";
d.hours = 5.8;
list_departments.Add(d);
d = new department();
d.name = "Finishing";
d.hours = 5.6;
list_departments.Add(d);
d = new department();
d.name = "QA";
d.hours = 0.5;
list_departments.Add(d);
Test = new part();
Test.name = "Cylinder";
Test.number = "234";
list_parts.Add(Test);
lv_parts.ItemsSource = list_parts;
}
}
My XAML of the listview without binding for the child list
<ListView x:Name="lv_parts" ItemsSource="{Binding list_parts}">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="50px"/>
<RowDefinition Height="50px"/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Content="{Binding number}"/>
<Label Grid.Row="1 " Content="{Binding name}"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The expected outcome would look something like this:
Without any visual styling like e.g. background and foreground colors, your ListView should look like shown below. It uses an ItemsControl with a horizontal StackPanel to show the Departments collection.
<ListView ItemsSource="{Binding Parts}">
<ListView.View>
<GridView>
<GridViewColumn>
<GridViewColumn.Header>
<TextBlock>
<Run Text="Part Number"/>
<LineBreak/>
<Run Text="Part Name"/>
</TextBlock>
</GridViewColumn.Header>
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock>
<Run Text="{Binding Number}"/>
<LineBreak/>
<Run Text="{Binding Name}"/>
</TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn>
<GridViewColumn.Header>
<TextBlock>
<Run Text="Departement Name"/>
<LineBreak/>
<Run Text="Hours"/>
</TextBlock>
</GridViewColumn.Header>
<GridViewColumn.CellTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding Departments}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock>
<Run Text="{Binding Name}"/>
<LineBreak/>
<Run Text="{Binding Hours}"/>
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
Note that the XAML above use a view model like shown below, with proper casing of class and property names.
public class Part
{
public string Number { get; set; }
public string Name { get; set; }
public List<Department> Departments { get; set; }
}
public class Department
{
public string Name { get; set; }
public double Hours { get; set; }
}
public class ViewModel
{
public ObservableCollection<Part> Parts { get; }
= new ObservableCollection<Part>();
}
An instance of the view model would be assigned to the DataContext of the view:
public MainWindow()
{
InitializeComponent();
var vm = new ViewModel();
DataContext = vm;
vm.Parts.Add(new Part
{
Name = "Block",
Number = "123",
Departments = new List<Department>
{
new Department { Name = "Sawing" , Hours = 0.3 },
new Department { Name = "Milling" , Hours = 12.3 },
}
});
vm.Parts.Add(new Part
{
Name = "Cylinder",
Number = "456",
Departments = new List<Department>
{
new Department { Name = "Sawing" , Hours = 1.2 },
new Department { Name = "Turning" , Hours = 5.8 },
new Department { Name = "Finishing" , Hours = 5.6 },
new Department { Name = "QA" , Hours = 0.5 },
}
});
}