Multiple levels of binding in WPF ItemsControl - wpf

How can i bind multiple levels of data in same time like List of chapters and under each chapter list of pages.
The class structure and xaml i used is shown here
public class ContentsPage
{
public string cname{ get; set; }
public string label { get; set; }
}
public class Chapter
{
public string name { get; set; }
public string id { get; set; }
public List<ContentsPage> pages { get; set; }
}
public class Model
{
public List<Chapter> chapters { get; set; }
}
<ItemsControl x:Name="TopLevelListBox" ItemsSource="{Binding}" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Expander ExpandDirection="Down" Width="175">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=name}" Margin="0,0,5,0"/>
</StackPanel>
</Expander.Header>
<ListBox x:Name="SubListBox" ItemsSource="{Binding Path=enrichments}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=cname}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Expander>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
For binding i used the code
Model data = new Model(); //load data
TopLevelListBox.DataContext = data.chapters;
Only my expander headers are filled with result. What i need to do fill the pages inside the expander ? Any ideas or samples link for doing the same

Your ItemsControl Item template should change a bit. Instead of setting the ListBox as Content of Expander, set it as Content Template.
<Expander ExpandDirection="Down"
Width="175" Content="{Binding}">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=name}"
Margin="0,0,5,0" />
</StackPanel>
</Expander.Header>
<Expander.ContentTemplate>
<DataTemplate>
<ListBox x:Name="SubListBox"
ItemsSource="{Binding Path=enrichments}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=cname}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DataTemplate>
</Expander.ContentTemplate>
</Expander>
And make sure you have sub items to show in ListBox.

Related

ListView SelectedItem does not get sychronized

I have following ListView and using MVVM Light
<ListView ItemsSource="{Binding Combinations, UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding Combination, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
Style="{StaticResource UserValueStyle}" SelectionMode="Single"
IsSynchronizedWithCurrentItem="True"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" ScrollViewer.HorizontalScrollBarVisibility="Disabled" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Text}" FontSize="20" Height="80" Width="100" FontWeight="Bold"
Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.OnUserValuePressed}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The property:
public SapInspectionUserValue Combination
{
get
{
return _combination;
}
set
{
_combination = value;
RaisePropertyChanged();
}
}
The class property:
public class SapInspectionUserValue
{
public string Combination { get; set; }
public string Value { get; set; }
public string Text { get; set; }
}
My problem is, when I select an item(in my case, press the button) the SelectedItem does not get synchronized and I do not know why. Whats is wrong?

Treeview Bindings Not Showing Second level

Hello I have a treeview that I am trying to diplay 2 levels deep.
The second level is not displaying
Here is the class and Collection from my VM
public class BuildTree
{
public int Id { get; set; }
public string Groups { get; set; }
public IEnumerable<myAreas> Areas { get; set; }
}
//Areas has a name property I want to show on the second level under the group
public ObservableCollection<BuildTree> MyObsvCollection
{
get { return _myCollection; }
}
Here is my Xaml
<TreeView ItemsSource="{Binding MyObsvCollection}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate>
<TextBlock Foreground="Red" Text="{Binding Groups}" />
<HierarchicalDataTemplate.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Areas}">
<TextBlock Text="{Binding Name}" />
</HierarchicalDataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
Your HierarchicalDataTemplate has no items to display. You should move ItemsSource to outer HierarchicalDataTemplate and then ItemTemplate can be simple DataTemplate
<HierarchicalDataTemplate ItemsSource="{Binding Areas}">
<TextBlock Foreground="Red" Text="{Binding Groups}" />
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>

XAML nested DataTemplate data-binding

I have an ItemsControl which has its ItemsSource set with a Binding to an ObservableCollection on my ViewModel. I am using a Button control within its ItemTemplate to display my data and I am using a DataTemplate within the Button and none of the Binding data is being displayed. Below is the XAML in question:
<ItemsControl ItemsSource="{Binding Path=ConnectedInstruments}" HorizontalAlignment="Left">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Height="60" VerticalAlignment="Top">
<Button.ContentTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=ModelCode}" />
<TextBlock Text="{Binding Path=SerialNumber}" />
</StackPanel>
</DataTemplate>
</Button.ContentTemplate>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Neither TextBlock controls within the Button DataTemplate are being populated. I understand this has something to do with the Binding path, however I am at a loss as to what I am doing wrong. Can someone put me on the right track please?
EDIT
public class Instrument
{
public string ModelCode { get; set; }
public string SerialNumber { get; set; }
}
public class ViewModel
{
public ObservableCollection<Instrument> ConnectedInstruments { get; set; }
}
I know that the ItemsControl is Binding correctly with the ObservableCollection as the correct count of Button controls are being displayed, only the templated data is missing.
Any specific reason you need to use ContentTemplate instead of directly setting Button's Content like this? :
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Height="60" VerticalAlignment="Top">
<StackPanel>
<TextBlock Text="{Binding Path=ModelCode}" />
<TextBlock Text="{Binding Path=SerialNumber}" />
</StackPanel>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>

Binding ItemsControl to ScrollViewer

At the begining I'll show some code:
private ObservableCollection<otwarteBezStolika> otwarteBezStolika = new ObservableCollection<otwarteBezStolika>();
public ObservableCollection<otwarteBezStolika> listunia
{
get { return otwarteBezStolika; }
set { otwarteBezStolika = value; }
}
}
public class otwarteBezStolika
{
public string number { get; set; }
public string date { get; set; }
public int orderID { get; set; }
public decimal price { get; set; }
public decimal priceR { get; set; }
public string opisRach { get; set; }
public string sum { get; set; }
}
And now in xaml:
<Window.Resources>
<DataTemplate x:Key="dataTempl">
<Border BorderBrush="Coral" BorderThickness="1" Width="170">
<Button Name="goToPOS" Tag="{Binding orderID}" Click="goToPOS_Click" Style="{StaticResource TabCloseButtonStyle}" Margin="1">
<StackPanel>
<Label Content="{Binding number}" HorizontalAlignment="Center" FontSize="15" FontWeight="ExtraBold" HorizontalContentAlignment="Center"></Label>
<Border BorderBrush="Turquoise" BorderThickness="1" Width="170"></Border>
<Label Content="{Binding date}" FontSize="12" HorizontalAlignment="Center"></Label>
<TextBlock Text="{Binding opisRach}" FontStyle="Italic" FontSize="12" Foreground="Black" TextAlignment="Center" TextWrapping="Wrap" Margin="0,0,0,2"></TextBlock>
<Border BorderBrush="WhiteSmoke" BorderThickness="1" Width="170"></Border>
<Label Content="{Binding sum}" FontSize="19" HorizontalAlignment="Center"></Label>
</StackPanel>
</Button>
</Border>
</DataTemplate>
<DataTemplate x:Key="mainTemplate">
<StackPanel>
<ItemsControl x:Name="imageContent" ItemsSource="{Binding listunia}" ItemTemplate="{StaticResource dataTempl}" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" ScrollViewer.HorizontalScrollBarVisibility="Disabled" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</StackPanel>
</DataTemplate>
</Window.Resources>
Grid:
<Grid Grid.Row="0">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<ItemsControl Name="templ" ItemsSource="{Binding ElementName=UI, Path=listunia }" ItemTemplate="{StaticResource mainTemplate}" />
</ScrollViewer>
</Grid>
Problem is that I cannot see any item (I'm filling items using sqldatareader, and adding them to list - by the way, does DataTable will also work? So instead while(rdr.Read()) i could ouse SqlDataAdapter sda and sda.fill(Datatable))
Second problem is that, it does work when I put "dataTempl" inside scrollviewer ,like :
<Grid Grid.Row="0">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<ItemsControl Name="templ" ItemsSource="{Binding ElementName=UI, Path=listunia }" ItemTemplate="{StaticResource dataTempl}" />
</ScrollViewer>
</Grid>
but items are show vertically, but I need to see them from left to right horizontal.
Thanks for answers!
Try doing this.. you dont need maintemplate.
<ScrollViewer VerticalScrollBarVisibility="Auto">
<ItemsControl Name="templ" ItemsSource="{Binding ElementName=UI, Path=listunia }" ItemTemplate="{StaticResource dataTempl}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" ScrollViewer.HorizontalScrollBarVisibility="Disabled" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</ScrollViewer>
OR you can simply use:
<ListBox Name="templ" ItemsSource="{Binding ElementName=UI, Path=listunia }" ItemTemplate="{StaticResource dataTempl}">
</ListBox>
<ScrollViewer VerticalScrollBarVisibility="Auto">
<ItemsControl Name="kaloo" DisplayMemberPath="Name" ss:DragDrop.IsDragSource="True" ss:DragDrop.IsDropTarget="True" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ScrollViewer>

WPF Relative Binding using hierarchical collection structure

I have an ObservableCollection containing an ObservableCollection:
public class BooksDetailModel
{
public BookModel Book{ get; set; }
public ObservableCollection<AuthorModel> Authors { get; set; }
}
Property in ViewModel:
public ObservableCollection<BooksDetailModel> Books { get; set; }
I would like to render this in a ListBox like this:
Book1
Author1
Author2
Book2
Author1
etc.
The top level bind is easy but I am having trouble with the inner child collection.
XAML so far:
<ListBox ItemsSource="{Binding Books}" BorderBrush="{x:Null}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Book.Name}" FontSize="12" FontWeight="Bold" />
<ListBox>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding ???, Path=Author.Name}" FontSize="10" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Any suggestions for ??? - Relative binding the inner listbox itemsource to the parent itemsource's Authors collection.
You should bind the ItemsSource of the inner ListBox to the Authors property. And the binding in the DataTemplate will be simply binding to the Name property of the author:
<ListBox ItemsSource="{Binding Books}" BorderBrush="{x:Null}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Book.Name}" FontSize="12" FontWeight="Bold" />
<ListBox ItemsSource="{Binding Authors}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" FontSize="10" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

Resources