Binding a list of object to a WPF listviewitem - c#

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 },
}
});
}

I made changes to your xaml code. You can change the stack panel to grid and add style as per your requirements
<Grid IsSharedSizeScope="True">
<ListView x:Name="lv_parts" ItemsSource="{Binding list_parts}">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" SharedSizeGroup="Parts"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Orientation="Vertical" Grid.Column="0" Background="CornflowerBlue">
<Label Content="{Binding number}" Foreground="AliceBlue"/>
<Label Content="{Binding name}" Foreground="AliceBlue"/>
</StackPanel>
<ListView Grid.Row="0" Grid.Column="1" Margin="0" ItemsSource="{Binding departments}" >
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical" Background="Coral">
<Label Content="{Binding name}" Foreground="AliceBlue"/>
<Label Content="{Binding hours}" Foreground="AliceBlue"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
The output is as below for the data that you gave:

Related

WPF Binding Listbox into ListView (different Source / datacontext)

i have these two classes.
classes:
public class OuterList
{
public string Process { get; set; }
public OuterList(string _process)
{
Process = _process;
}
}
public class InnerList
{
public string Order { get; set; }
public string Product { get; set; }
public InnerList(string _order, string _product)
{
Order = _order;
Product = _product;
}
}
And i will get a Listbox in a ListView.
XAML:
<ListView x:Name="Container" ItemsSource="{Binding OuterList}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Margin="5" FontSize="24" FontFamily="Arial" Background="Red" Text="{Binding Process}"/>
<ListBox x:Name="Orders" ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=Grid}, Path=DataContext.InnerList}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Product}"/>
<TextBlock Text="{Binding Order}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Code:
public partial class MainWindow : Window
{
ObservableCollection<OuterList> myContainers = new();
ObservableCollection<InnerList> myItems = new();
public MainWindow()
{
InitializeComponent();
myContainers.Add(new OuterList("Start"));
myContainers.Add(new OuterList("Middle"));
myContainers.Add(new OuterList("End"));
Container.ItemsSource = myContainers;
myItems.Add(new InnerList("34545","SD5"));
myItems.Add(new InnerList("45654", "SD5"));
myItems.Add(new InnerList("65775", "SD5"));
myItems.Add(new InnerList("78677", "SD5"));
myItems.Add(new InnerList("35887", "SD5"));
Orders.ItemsSource = myItems; //<- The name "Orders" does not exist in the current context.
}
}
All the Content of the OuterList will shown, but no Item from InnerList
How can i add Content from two different ItemSources? Or, what am I doing wrong?
Got an issue in Code: The name "Orders" does not exist in the current context.
Thanks for you Help!
Because your DataContext is incorrect.
Assuming the Grid that wraps both of them its DataContext contains Outer and Inner
You can do this:
<Grid>
<ListView x:Name="Container" ItemsSource="{Binding OuterList}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Margin="5" FontSize="24" FontFamily="Arial" Background="Red" Text="{Binding Process}"/>
<ListBox x:Name="Orders" ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=Grid}, Path=DataContext.InnerList}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Product}"/>
<TextBlock Text="{Binding Order}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>

WPF Data Binding with Subclass

I trying to get into WPF so for that I was trying to get a good example for myself to start with. After a few tries I started to get a bit confused about how the databinding in WFP works.
Here my example:
Lets say i got a 3 classes in my project:
Product
Category
Tags
So for that I got these classes here:
Category:
public class Category
{
private int id;
private string name;
public int Id { get => id; set => id = value; }
public string Name { get => name; set => name = value; }
}
Tags:
public class Tag
{
private int id;
private string name;
public int Id { get => id; set => id = value; }
public string Name { get => name; set => name = value; }
}
Product:
public class Product
{
private int id;
private string name;
private double price;
private int categoryID;
private ICollection<Tag> tags;
public int Id { get => id; set => id = value; }
public string Name { get => name; set => name = value; }
public double Price { get => price; set => price = value; }
public int CategoryID { get => categoryID; set => categoryID = value; }
public ICollection<Tag> Tags { get => tags; set => tags = value; }
public Category Category
{
get => default(Category);
set{}
}
}
Lets say I got the data from somewhere to fill these classes:
List<Product> products = new List<Product>();
products.Add(new Product() { Id = 1, Name = "Toy Car", Price = 14.99,
CategoryID = 2, Tags = new List<Tag>() { new Tag { Id = 1, Name = "Toy" },
new Tag { Id = 2, Name = "Kids" } } });
products.Add(new Product() { Id = 1, Name = "Water", Price = 14.99,
CategoryID = 2, Tags = new List<Tag>() { new Tag { Id = 3, Name = "Food" } }
});
List<Category> categories = new List<Category>();
categories.Add(new Category() { Id = 1, Name = "Food" });
categories.Add(new Category() { Id = 2, Name = "Toys" });
My UI looks like this:
MainWindow.xaml:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:wfp_test"x:Class="wfp_test.MainWindow"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800" Loaded="Window_Loaded">
<Window.Resources>
<CollectionViewSource x:Key="productViewSource" d:DesignSource="{d:DesignInstance {x:Type local:Product}, CreateList=True}"/>
<CollectionViewSource x:Key="productTagsViewSource" Source="{Binding Tags, Source={StaticResource productViewSource}}"/>
</Window.Resources>
<Grid DataContext="{StaticResource productTagsViewSource}" >
<Grid x:Name="grid1" DataContext="{StaticResource productViewSource}" HorizontalAlignment="Left" Margin="13,154,0,0" VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label Content="Category:" Grid.Column="0" HorizontalAlignment="Left" Margin="3" Grid.Row="0" VerticalAlignment="Center"/>
<ComboBox x:Name="categoryComboBox" Grid.Column="1" DisplayMemberPath="Category" HorizontalAlignment="Left" Height="Auto" ItemsSource="{Binding}" Margin="3" Grid.Row="0" VerticalAlignment="Center" Width="120">
<ComboBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel/>
</ItemsPanelTemplate>
</ComboBox.ItemsPanel>
</ComboBox>
<Label Content="Id:" Grid.Column="0" HorizontalAlignment="Left" Margin="3" Grid.Row="2" VerticalAlignment="Center"/>
<TextBox x:Name="idTextBox" Grid.Column="1" HorizontalAlignment="Left" Height="23" Margin="3" Grid.Row="2" Text="{Binding Id, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}" VerticalAlignment="Center" Width="120"/>
<Label Content="Name:" Grid.Column="0" HorizontalAlignment="Left" Margin="3" Grid.Row="3" VerticalAlignment="Center"/>
<TextBox x:Name="nameTextBox" Grid.Column="1" HorizontalAlignment="Left" Height="23" Margin="3" Grid.Row="3" Text="{Binding Name, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}" VerticalAlignment="Center" Width="120"/>
<Label Content="Price:" Grid.Column="0" HorizontalAlignment="Left" Margin="3" Grid.Row="4" VerticalAlignment="Center"/>
<TextBox x:Name="priceTextBox" Grid.Column="1" HorizontalAlignment="Left" Height="23" Margin="3" Grid.Row="4" Text="{Binding Price, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}" VerticalAlignment="Center" Width="120"/>
</Grid>
<DataGrid x:Name="tagsDataGrid" AutoGenerateColumns="False" EnableRowVirtualization="True" ItemsSource="{Binding}" Margin="382,155,10,64" RowDetailsVisibilityMode="VisibleWhenSelected">
<DataGrid.Columns>
<DataGridTextColumn x:Name="idColumn" Binding="{Binding Id}" Header="Id" Width="SizeToHeader"/>
<DataGridTextColumn x:Name="nameColumn" Binding="{Binding Name}" Header="Name" Width="SizeToHeader"/>
</DataGrid.Columns>
</DataGrid>
<ListView x:Name="productListView" ItemsSource="{Binding Source={StaticResource productViewSource}}" Margin="10,10,10,296" SelectionMode="Single">
<ListView.ItemContainerStyle>
<Style>
<Setter Property="Control.HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="Control.VerticalContentAlignment" Value="Stretch"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView>
<GridViewColumn x:Name="categoryColumn" Header="Category" Width="80">
<GridViewColumn.CellTemplate>
<DataTemplate>
<ComboBox Margin="6,-1,-6,-1">
<ComboBoxItem Content="{Binding Category}"/>
</ComboBox>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn x:Name="categoryIDColumn" Header="Category ID" Width="80">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBox Margin="-6,-1" Text="{Binding CategoryID, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn x:Name="idColumn1" Header="Id" Width="80">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBox Margin="-6,-1" Text="{Binding Id, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn x:Name="nameColumn1" Header="Name" Width="80">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBox Margin="-6,-1" Text="{Binding Name, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn x:Name="priceColumn" Header="Price" Width="80">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBox Margin="-6,-1" Text="{Binding Price, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Grid>
MainWindow.xaml.cs:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
List<Product> products = new List<Product>();
products.Add(new Product() { Id = 1, Name = "Toy Car", Price = 14.99, CategoryID = 2, Tags = new List<Tag>() { new Tag { Id = 1, Name = "Toy" }, new Tag { Id = 2, Name = "Kids" } } });
products.Add(new Product() { Id = 1, Name = "Water", Price = 14.99, CategoryID = 1, Tags = new List<Tag>() { new Tag { Id = 3, Name = "Food" } } });
List<Category> categories = new List<Category>();
categories.Add(new Category() { Id = 1, Name = "Food" });
categories.Add(new Category() { Id = 2, Name = "Toys" });
System.Windows.Data.CollectionViewSource productViewSource = ((System.Windows.Data.CollectionViewSource)(this.FindResource("productViewSource")));
categoryComboBox.ItemsSource = categories;
productViewSource.Source = products;
}
}
My first problem here the categoryComboBox is always empty. My second problem ist how do I set the ValueMember and DisplayMember of this box and where can I fill it with the Data from categories?
The DisplayMemberPath should be set to "Name". You may also set SelectedValuePath to "Id":
<ComboBox x:Name="categoryComboBox" DisplayMemberPath="Name" SelectedValuePath="Id" ... />

(some) bindings and datatemplates (with datatype specified) not working

I have a such XAML defined:
<UserControl x:Class="auditsListTest.AuditsList"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:auditsListTest"
xmlns:local2="clr-namespace:auditsTest"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="300">
<UserControl.Resources>
<DataTemplate DataType="local2:AnomalyComplex">
<DockPanel>
<DockPanel DockPanel.Dock="Top">
<TextBlock DockPanel.Dock="Left"
Text="{Binding Value.Description}" />
<ComboBox DockPanel.Dock="Right">
<ComboBoxItem Content="Fix" />
<ComboBoxItem Content="Fix 2" />
</ComboBox>
<Image DockPanel.Dock="Right"/>
<Button DockPanel.Dock="Right">
<TextBlock Text="Allow" />
</Button>
</DockPanel>
<ListBox ItemsSource="{Binding Value.GroupDescriptions}">
<ListBoxItem>
<DataTemplate>
<Expander Header="{Binding Key}" >
<DataTemplate>
<ListBox ItemsSource="{Binding Value}" />
</DataTemplate>
</Expander>
</DataTemplate>
</ListBoxItem>
</ListBox>
</DockPanel>
</DataTemplate>
<DataTemplate DataType="local2:AnomalyStandard">
<DockPanel DockPanel.Dock="Top">
<TextBlock DockPanel.Dock="Left"
Text="{Binding Value.Description}" />
<ComboBox DockPanel.Dock="Right">
<ComboBoxItem Content="Fix" />
<ComboBoxItem Content="Fix 2" />
</ComboBox>
<Image DockPanel.Dock="Right" />
<Button DockPanel.Dock="Right">
<TextBlock Text="Allow" />
</Button>
<TextBlock DockPanel.Dock="Bottom"
Text="{Binding Value.DescriptionDetailed}" />
</DockPanel>
</DataTemplate>
</UserControl.Resources>
<DockPanel Background="#FFA6FDE9">
<TextBlock DockPanel.Dock="Top">Kontrolka audits</TextBlock>
<ItemsControl HorizontalContentAlignment="Stretch"
x:Name="Tree"
DockPanel.Dock="Top"
ItemsSource="{Binding Anomalies}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Expander Name="expander"
Loaded="expander_Loaded" IsExpanded="True" >
<Expander.HeaderTemplate>
<DataTemplate>
<DockPanel LastChildFill="True"
HorizontalAlignment="Stretch">
<TextBlock DockPanel.Dock="Left"
Text="{Binding Key}" />
<TextBlock DockPanel.Dock="Right"
HorizontalAlignment="Right">
<Run Text="Issues " />
<Run Text="{Binding Value.Count}" />
</TextBlock>
</DockPanel>
</DataTemplate>
</Expander.HeaderTemplate>
<ContentControl>
<ItemsControl ItemsSource="{Binding Value}" />
</ContentControl>
</Expander>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DockPanel>
</UserControl>
with below code-behind:
public partial class AuditsList : UserControl
{
public List<Anomaly> anomalies { get; set; }
public Lookup<string, Anomaly> groupedAnomalies { get; set; }
public List<KeyValuePair<string, List<Anomaly>>> groupedAnomalies2 { get; set; }
public AuditsList()
{
groupedAnomalies2 = ReturnData();
DataContext = new
{
Anomalies = groupedAnomalies2
};
InitializeComponent();
}
private List<KeyValuePair<string, List<Anomaly>>> ReturnData()
{
List<KeyValuePair<string, List<Anomaly>>> aaa = new List<KeyValuePair<string, List<Anomaly>>>();
Slide sld1 = new Slide();
sld1.Name = "slide1";
sld1.SlideIndex = 1;
Slide sld2 = new Slide();
sld1.Name = "slide2";
sld1.SlideIndex = 2;
Slide sld3 = new Slide();
sld1.Name = "slide3";
sld1.SlideIndex = 3;
Audit au1 = new Audit();
au1.Description = "desc1";
au1.Name = "audit1";
au1.Priority = 1;
Audit au2 = new Audit();
au2.Description = "desc2";
au2.Name = "audit2";
au2.Priority = 2;
List<string> descs1 = new List<string>();
descs1.Add("Wlazł kotek na płotek");
descs1.Add("Ala ma kota");
KeyValuePair<string, List<string>> kvp1 = new KeyValuePair<string, List<string>>("Polski", descs1);
List<string> descs2 = new List<string>();
descs2.Add("Good morning captain!");
descs2.Add("Fly! Fly! Fly away!");
KeyValuePair<string, List<string>> kvp2 = new KeyValuePair<string, List<string>>("English", descs2);
List<string> descs3 = new List<string>();
descs3.Add("keine scheise!");
descs3.Add("spreche dreche");
KeyValuePair<string, List<string>> kvp3 = new KeyValuePair<string, List<string>>("Deutsch", descs1);
AnomalyComplex ano1 = new AnomalyComplex();
ano1.Audit = au1;
ano1.Name = au1.Name;
ano1.Description = au1.Name;
ano1.Slide = sld1;
ano1.GroupDescriptions = new List<KeyValuePair<string, List<string>>>();
ano1.GroupDescriptions.Add(kvp1);
ano1.GroupDescriptions.Add(kvp2);
ano1.GroupDescriptions.Add(kvp3);
AnomalyStandard ano2 = new AnomalyStandard();
ano2.Audit = au2;
ano2.Name = au2.Name;
ano2.Slide = sld2;
ano2.DescriptionDetailed = "trele morele";
ano2.Description = au2.Name;
AnomalyStandard ano3 = new AnomalyStandard();
ano3.Audit = au2;
ano3.Name = au2.Name;
ano3.Slide = sld3;
ano3.Description = au2.Name;
ano3.DescriptionDetailed = "bomba trąba";
anomalies = new List<Anomaly>();
anomalies.Add(ano1);
anomalies.Add(ano2);
anomalies.Add(ano3);
groupedAnomalies = (Lookup<string, Anomaly>)anomalies.OrderBy(c => c.Audit.Priority).ToLookup(c => c.Audit.Priority == 1 ? "Slide " + c.Slide.SlideIndex.ToString() : "Presentation");
aaa = groupedAnomalies.Select(c => new KeyValuePair<string, List<Anomaly>>(c.Key, c.ToList())).ToList();
return aaa;
}
}
I have also defined below classes:
namespace auditsListTest
{
public class Slide
{
public int SlideIndex { get; set; }
public string Name { get; set; }
}
}
public class Audit
{
public string Name { get; set; }
public string Description { get; set; }
public int Priority { get; set; }
public virtual List<Anomaly> PerformAudit(double progress)
{
return new List<Anomaly>();
}
}
public class Anomaly
{
public string Name { get; set; }
public Audit Audit { get; set; }
public string Description { get; set; }
public bool Fixed { get; set; }
public bool Allowed { get; set; }
public string Container { get; set; }
public Slide Slide { get; set; }
public void Fix()
{
Fixed = true;
}
public void Allow()
{
Allowed = true;
}
}
public class AnomalyComplex : Anomaly
{
public List<KeyValuePair<string, List<string>>> GroupDescriptions { get; set; }
}
public class AnomalyStandard : Anomaly
{
public string DescriptionDetailed { get; set; }
}
What is the problem? First, textblocks with binding defined in Expander.HeaderTemplate are not showing values.
<TextBlock DockPanel.Dock="Left"
Text="{Binding Key}" />
<TextBlock DockPanel.Dock="Right"
HorizontalAlignment="Right">
<Run Text="Issues " />
<Run Text="{Binding Value.Count}" />
Second problem is with datatemplates with datatypes (DataType="local2:AnomalyComplex" and DataType="local2:AnomalyStandard") that are not automatically used. Should I use DataTemplateSelectors?
<ContentControl>
<ItemsControl ItemsSource="{Binding Value}" />
</ContentControl>
Could you analyze code and let me know where is problem, and how to solve it? Thanks in advance.
First, textblocks with binding defined in Expander.HeaderTemplate are not showing values.
Bind the Header property to the KeyValuePair<string, List<Anomaly>>:
<Expander Name="expander" Header="{Binding}">
<Expander.HeaderTemplate>
<DataTemplate>
<DockPanel LastChildFill="True" HorizontalAlignment="Stretch">
<TextBlock DockPanel.Dock="Left" Text="{Binding Key}" />
<TextBlock DockPanel.Dock="Right" HorizontalAlignment="Right">
<Run Text="Issues " />
<Run Text="{Binding Value.Count, Mode=OneTime}" />
</TextBlock>
</DockPanel>
</DataTemplate>
</Expander.HeaderTemplate>
...
</Expander>
In case of DataTemplates with specified DataTypes, it should be specified inside curly braces, for example:
<DataTemplate DataType="{x:Type local2:AnomalyComplex}">
<DataTemplate DataType="{x:Type local2:AnomalyStandard}">

Longlist is not populated with items

I'm trying to populate the Longlist via WCF following this tutorial. I want to group users by their income (from min to max), but groups are displayed randomly. Also there are no items in the list (see picture below). What am I missing?
My XAML code is:
<phone:PhoneApplicationPage.Resources>
<phone:JumpListItemBackgroundConverter x:Key="BackgroundConverter"/>
<phone:JumpListItemForegroundConverter x:Key="ForegroundConverter"/>
<DataTemplate x:Key="usersHeaderTemplate">
<Border Width="72" Height="72" HorizontalAlignment="Left" Background="{Binding Converter={StaticResource BackgroundConverter}}" Margin="6">
<TextBlock Text="{Binding Income}"
FontSize="20" Padding="6"
VerticalAlignment="Center" HorizontalAlignment="Center"
Foreground="{Binding Converter={StaticResource ForegroundConverter}}" />
</Border>
</DataTemplate>
<DataTemplate x:Key="usersItemTemplate">
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Flag}" Height="50" Margin="0,0,10,0"/>
<StackPanel>
<TextBlock Text="{Binding Name}" Style="{StaticResource PhoneTextSubtleStyle}" />
<TextBlock Text="{Binding Income,StringFormat='Income: {0}'}" />
<TextBlock Text="{Binding Job}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
<Style x:Key="LongListSelectorJumpListStyle" TargetType="phone:LongListSelector">
<Setter Property="GridCellSize" Value="113,113"/>
<Setter Property="LayoutMode" Value="Grid" />
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<Border Background="{Binding Converter={StaticResource BackgroundConverter}}"
Width="113" Height="113" Margin="6" >
<TextBlock Text="{Binding Title}"
FontFamily="{StaticResource PhoneFontFamilySemiBold}"
FontSize="48" Padding="6"
Foreground="{Binding Converter={StaticResource ForegroundConverter}}"
VerticalAlignment="Center"/>
</Border>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
<DataTemplate x:Key="usersListHeader">
<Border Background="White" Opacity="0.2" Height="70">
<TextBlock Text="List Header" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="Black" />
</Border>
</DataTemplate>
<DataTemplate x:Key="usersListFooter">
<Border Background="White" Opacity="0.2" Height="70">
<TextBlock Text="List Footer" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="Black"/>
</Border>
</DataTemplate>
</phone:PhoneApplicationPage.Resources>
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<phone:LongListSelector x:Name="longlist2" Height="608" Margin="10,15,24,0" VerticalAlignment="Top" Width="422"
IsGroupingEnabled="True" LayoutMode="List" HideEmptyGroups="False"
ItemTemplate="{StaticResource usersItemTemplate}"
GroupHeaderTemplate="{StaticResource usersHeaderTemplate}"
JumpListStyle="{StaticResource LongListSelectorJumpListStyle}"
ListHeaderTemplate="{StaticResource usersListHeader}"
ListFooterTemplate="{StaticResource usersListFooter}" >
</phone:LongListSelector>
</Grid>
</Grid>
My service implementation is:
public IEnumerable<mTeachers> GetStuffList(string Job)
{
List<mTeachers> stuffList = new List<mTeachers>();
DataClasses1DataContext data = new DataClasses1DataContext();
List<mTeachers> finalList = new List<mTeachers>();
foreach (var d in data.Stuffs)
{
stuffList.Add(new mTeachers() { Name = d.stuffName, Income = (int)d.stuffIncome, Job = Job, Flag = new Uri(#"/Assets/users.png", UriKind.Relative) });
}
return stuffList;
}
private List<Group<mTeachers>> GetUsersGroups(string Job)
{
IEnumerable<mTeachers> usersList = GetStuffList(Job);
return GetItemGroups(usersList, c => c.Income);
}
private static List<Group<T>> GetItemGroups<T>(IEnumerable<T> itemList, Func<T, int> getKeyFunc)
{
IEnumerable<Group<T>> groupList = from item in itemList
group item by getKeyFunc(item) into g
orderby g.Key
select new Group<T>(g.Key, g);
return groupList.ToList();
}
public class Group<T> : List<T>
{
public Group(int income, IEnumerable<T> items)
: base(items)
{
this.Income = income;
}
public int Income
{
get;
set;
}
}
My service interface:
[OperationContract]
IEnumerable<mTeachers> GetStuffList(string Job);
}
[DataContract]
public class mTeachers
{
[DataMember]
public string Name { get; set; }
[DataMember]
public int Income { get; set; }
[DataMember]
public string Job { get; set; }
[DataMember]
public System.Uri Flag { get; set; }
}
EDIT: WP page code:
public MainPage()
{
InitializeComponent();
ServiceReference1.Service1Client proxy = new ServiceReference1.Service1Client();
proxy.GetStuffListCompleted += showList;
proxy.GetStuffListAsync("teacher");
}
private void showList(object sender, ServiceReference1.GetStuffListCompletedEventArgs e)
{
this.longlist2.ItemsSource = e.Result;
}
Add ItemsSource="{Binding}" to the LongListSelector declaration in your XAML. So it should look like this.
<phone:LongListSelector x:Name="longlist2" Height="608" Margin="10,15,24,0" VerticalAlignment="Top" Width="422"
IsGroupingEnabled="True" LayoutMode="List" HideEmptyGroups="False"
ItemTemplate="{StaticResource usersItemTemplate}"
GroupHeaderTemplate="{StaticResource usersHeaderTemplate}"
JumpListStyle="{StaticResource LongListSelectorJumpListStyle}"
ListHeaderTemplate="{StaticResource usersListHeader}"
ListFooterTemplate="{StaticResource usersListFooter}"
ItemsSource="{Binding}" >
</phone:LongListSelector>
I think there are two things going on here.
First I think your GetStuffList(string Job) function is doing something weird, please check the return values to see if it's exactly what you want.
Second I think the ItemSource needs to be set like KasunKV said.
Here are my fixes and the resulting screenshot showing it works.
// create a static group list to see if it works
private List<Group<mTeachers>> GetUsersGroups(string Job)
{
List<mTeachers> usersList = new List<mTeachers>();
usersList.Add(new mTeachers() { Name = "Bob", Income = 1000, Flag = new Uri(#"/Assets/AlignmentGrid.png", UriKind.Relative), Job = "Guy" });
usersList.Add(new mTeachers() { Name = "Dan", Income = 1000, Flag = new Uri(#"/Assets/AlignmentGrid.png", UriKind.Relative), Job = "Guy" });
usersList.Add(new mTeachers() { Name = "Kate", Income = 2000, Flag = new Uri(#"/Assets/AlignmentGrid.png", UriKind.Relative), Job = "Girl" });
usersList.Add(new mTeachers() { Name = "Charlie", Income = 2000, Flag = new Uri(#"/Assets/AlignmentGrid.png", UriKind.Relative), Job = "Guy" });
usersList.Add(new mTeachers() { Name = "Jeff", Income = 2000, Flag = new Uri(#"/Assets/AlignmentGrid.png", UriKind.Relative), Job = "Guy" });
usersList.Add(new mTeachers() { Name = "Jeff2", Flag = new Uri(#"/Assets/AlignmentGrid.png", UriKind.Relative), Job = "Guy" });
return GetItemGroups(usersList, c => c.Income);
}
// Constructor
public MainPage()
{
InitializeComponent();
// create the user group and bind it to item source
this.longlist2.ItemsSource = GetUsersGroups("whatever");
}
Results of the change can be view here:

Binding ListView SelectedItem between two or more ListViews

I have a Dictionary that contains an ObservableCollection like this:
Dictionary<string, ObservableCollection<Person>> MyDictionary
Now in my xaml, I'm creating an itemscontrol that uses the dictionary's key for an expander and the person's collection in a listview something like this:
<ItemsControl ItemsSource="{Binding MyDictionary}" VerticalAlignment="Center" HorizontalAlignment="Left">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Expander Name="expander" IsExpanded="True">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Margin="5" VerticalAlignment="Stretch" HorizontalAlignment="Left" Text="MyString:"/>
<TextBlock Margin="5" VerticalAlignment="Stretch" HorizontalAlignment="Left" Text="{Binding Key}"/>
</StackPanel>
</Expander.Header>
<Expander.Content>
<ListView SelectionMode="Single" ItemsSource="{Binding Value}">
<ListView.View>
<GridView AllowsColumnReorder="True">
<GridViewColumn>
<GridViewColumn.Header>
<TextBlock Text="Name" Margin="5" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</GridViewColumn.Header>
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" Margin="5" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn>
<GridViewColumn.Header>
<TextBlock Text="Last Name" Margin="5" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</GridViewColumn.Header>
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding LastName}" Margin="5" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Expander.Content>
</Expander>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Now, as you can see it creates a collection of expanders and each expander has a listview within it's content...
I want to let only one listview have a selected item, how can I do it?
If I wasn't clear: I will have 3 Expanders, each one has 1 ListView, each ListView has 4-5 item's, i want that when a user click on a listviewitem all other ListViews selected items will be unselected.
Thanks !
Why don't you subscribe to the selection event of each list view and call UnselectAll on the others.
Hey I have an idea to do this . Bind the SelectedItem of all the listBox to same SelectedItemProperty of ViewModel like
>xaml here I have two ListBox whose SelectedItem is bound to same property of VM
<StackPanel Height="500" Width="500">
<ListBox Height="200" ItemsSource="{Binding StudentList1}" DisplayMemberPath="Name" SelectedItem="{Binding SelectedStudent}"></ListBox>
<ListBox Height="200" ItemsSource="{Binding StudentList2}" DisplayMemberPath="Name" SelectedItem="{Binding SelectedStudent}"></ListBox>
</StackPanel>
xaml.cs
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel();
}
ViewModel
public class ViewModel:INotifyPropertyChanged
{
public ViewModel()
{
StudentList1 = new ObservableCollection<Student>();
StudentList1.Add(new Student() { Name = "abc", Age = 20 });
StudentList1.Add(new Student() { Name = "abc", Age = 20 });
StudentList1.Add(new Student() { Name = "abc", Age = 20 });
StudentList2 = new ObservableCollection<Student>();
StudentList2.Add(new Student() { Name = "xyz", Age = 30 });
StudentList2.Add(new Student() { Name = "xyz", Age = 30 });
StudentList2.Add(new Student() { Name = "xyz", Age = 30 });
}
public ObservableCollection<Student> StudentList1 { get; set; }
public ObservableCollection<Student> StudentList2 { get; set; }
Student selectedStudent;
public Student SelectedStudent
{
get { return selectedStudent; }
set { selectedStudent = value; Notify("SelectedStudent"); }
}
public void Notify(string propName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
Student Class
public class Student
{
public string Name { get; set; }
public int Age { get; set; }
}
I hope you got an idea .SelectedItem works on the basis of References when you will select one Listbox item the SelectedStudent property of VM will get updated and hence all othe ListBox SelectedItem will get deselected because they dont have this reference in there itemssource. The power of MVVM :)
>Update
Student selectedStudent1;
public Student SelectedStudent1
{
get { return selectedStudent1; }
set {
selectedStudent=null;
selectedStudent1 = value;
Notify("SelectedStudent1"); }
}
Student selectedStudent;
public Student SelectedStudent
{
get { return selectedStudent; }
set {
selectedStudent1=null;
selectedStudent = value;
Notify("SelectedStudent"); }
}

Categories