WPF - adding user control to listbox - wpf

I am trying to add a usercontrol to a ListBox.
My usercontrol contains a collection of basic elements like textbox and dropdowns, in a fashion so that it creates a row of elements.
The code for ListBox in my main window is as -
<GroupBox FontWeight="SemiBold" Foreground="#FF0CAEF9" Name="gbAddProducts" Style="{x:Null}" Header="ADD PRODUCTS" HorizontalAlignment="Left" Margin="0,256,0,0" VerticalAlignment="Top" Width="990" Height="207">
<ListBox Name="lstboxAddProduct" ItemsSource="{Binding Path=AddNewProductRowViewModelList, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" BorderThickness="0" Margin="0,10,-2,23">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<ContentControl Content="{Binding AddNewProductRowViewModel}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<Validation.ErrorTemplate>
<ControlTemplate>
<StackPanel>
<AdornedElementPlaceholder x:Name="aepForError"/>
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding ErrorContent}" Foreground="White" Background="#DC000C" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ControlTemplate>
</Validation.ErrorTemplate>
</ListBox>
</GroupBox>
Here AddNewProductRowViewModelList is my user control list containing 5 controls.
The Problem that I see is that when I run the code, the screen has 5 rows, ie I can click on the area to figure out theer are 5 rows as that section gets highlighted. But they are not visible.
Could it be some 'bring to front' sort of issue.
Please advise.
Thanks in advance.

I would do it this way instead:
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<ContentControl>
<local:AddNewProductRowView Datacontext="{Binding AddNewProductRowViewModel}"/>
</ContentControl>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>

Related

Use CollectionViewSource with TabControl

I'm trying to group and display the items of an ObservableCollection, just by using XAML code. It works well using a simple CollectionViewSource and a ListBox[1].
Actually, I would prefer to display the group's content in a tabcontrol. Google led me to the following social.msdn article wich presents a workaround to display the groups as a TabControl using code behind:
https://social.msdn.microsoft.com/Forums/vstudio/en-US/e073f275-0826-4fca-b9da-e310ccf1713e/wpf-grouping?forum=wpf
However, as I'm using MVVM and must rely on xaml only, I can't get it to work. Actually, the CollectionViewSource populates the groups (the TabControl shows the correct tabItemHeaders), but clicking on any of these TabItems freezes the application. Here's what I've tried:
<StackPanel x:Key="ModulSelectInputParameterView">
<StackPanel.Resources>
<CollectionViewSource x:Key="cvs" x:Name="collectionViewSource" Source="{Binding ReferencedLmtItem.ModulInputParameterCollection }">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="Category"/>
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</StackPanel.Resources>
<Grid >
<TabControl ItemsSource="{Binding Source={StaticResource cvs}, Path=Groups, Mode=OneWay}" DataContext="{Binding Source={StaticResource cvs}, Mode=OneWay}">
<!-- First Level -->
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<ListBox ItemsSource="{Binding Items}">
Second Level
<ListBox.ItemTemplate>
<DataTemplate>
<Expander Header="{Binding Name}">
<ListBox ItemsSource="{Binding Items}">
The Item of the Collection
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Key}"/>
<TextBlock Text=" - "/>
<TextBlock Text="{Binding Value.Comment}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Expander>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</Grid>
</StackPanel>
[1]: This peace of xaml does work as expected, but uses a wrappanel to display groups contents:
<StackPanel x:Key="ModulSelectInputParameterView">
<StackPanel.Resources>
<CollectionViewSource x:Key="cvs" x:Name="collectionViewSource" Source="{Binding ReferencedLmtItem.ModulInputParameterCollection }">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="Category"/>
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</StackPanel.Resources>
<ListBox ItemsSource="{Binding Source={StaticResource cvs}}" VerticalContentAlignment="Top" ItemContainerStyle="{StaticResource ModulSelectInputParameterListBoxItemContainerStyle}" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListBox.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<Border BorderBrush="DarkGray" BorderThickness="2" Margin="2">
<TextBlock FontWeight="Bold" FontSize="14" Text="{Binding Path=Name}" HorizontalAlignment="Center" MinWidth="100"/>
</Border>
</DataTemplate>
</GroupStyle.HeaderTemplate>
<GroupStyle.Panel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" Margin="2"/>
</ItemsPanelTemplate>
</GroupStyle.Panel>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Border BorderThickness="2" BorderBrush="DarkGray">
<StackPanel>
<ContentPresenter Content="{TemplateBinding ContentControl.Content}" ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}" ContentStringFormat="{TemplateBinding ContentControl.ContentStringFormat}" />
<ItemsPresenter Margin="2,0,2,2" />
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListBox.GroupStyle>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True" Orientation="Vertical" VerticalAlignment="Top"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
</StackPanel>
I think there's something wrong with your binding your code should work.
To get the same items in both ListBoxes try to bind the second ListBox Itemssource to the first ListBox Itemssource like this :
<ListBox ItemsSource="{Binding Items}" Name="ListBox">
<ListBox.ItemTemplate>
<DataTemplate>
<Expander Header="{Binding Key}">
<ListBox ItemsSource="{Binding ItemsSource, ElementName=ListBox}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Key}"/>
<TextBlock Text=" - "/>
<TextBlock Text="{Binding Value}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Expander>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Thanks to Joh who helped with the appropriate DataBinding. However, the reason was totally different, a quick and dirty solution is given below[1]:
Basically, I was missing that the above mentioned tab control is nested within an outer Tab Control in my main window. I am not toally sure if the following description is entirely correct[1], but to my mind the reason is the following:
The outer TabControl uses a style to display its content. This content applies to a ViewModel which holds the above mentioned observable collection, which in turn should be the ItemsSource of the CollectionViewSource that feeds the inner tabControl with the groups.
As I have defined this style only in the outer TabControl.Resources, and missed to define a separate style for the inner tab Control, the inner tabcontrol inherits the outer style and tries to display its data using the same content.
This content is again another inner tabControl, which calls another inner tabControl and so on.
[1] Defining an empty style in the inenr tabControl.Resources solved the problem:
<TabControl.Resources>
<Style TargetType="TabItem">
</Style>
</TabControl.Resources>
I would be happy if someone could confirm this idea or provide some links to well known issues with shared styles in nested controls.

VirtualizingStackPanel is working fine in ListView's ItemPanel. But not the simple StackPanel

I just want to display Items in ListView like windows explorer (Large icons). For the same I used the below code.
<ListView Name="lstView" ItemsSource="{Binding MovieList}" >
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<!-- <VirtualizingStackPanel/> --> <!-- Working Fine -->
<StackPanel/> <!-- Items are not displayed -->
<!-- It must be wrap panel -->
<!-- OK, lets see with simple -->
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Label Content="{Binding Path}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
In the above code, If I use VirtualizingStackPanel then the items are displayed fine, but one by one which I don't want. If I use StackPanel, the items are not dispalyed in screen, even the items are not added in StackPanel. I checked with Snoop tool.
I should use WrapPanel instread of StackPanel to list items, but lets see the simple StackPanel.
Why the items are not displayed in StackPanel?
Basically I want list the items like WindowExplorer large icon view.
I am using .NET 4.0
I tried same thing in my code and it's working fine. Virtualization works as long as size of the ItemsControl's viewport is restricted.
just try replacing the code given below:
<ListView ItemsSource="{Binding Movies}" Width="400" HorizontalAlignment="Left" >
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel VirtualizingPanel.IsVirtualizing="True" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Year}" FontSize="12" Margin="10,0,0,0"/>
<TextBlock Text="{Binding Name}" FontSize="12" Margin="10,0,0,0"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Category}" FontSize="12" Margin="10,0,0,0"/>
<TextBlock Text="{Binding Director}" FontSize="12" Margin="10,0,0,0"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

Dynamically adding controls to View from MVVM

In WPF, I am using the MVVM model.
I have a View with a Dockpanel and I want to add dynamically StackPanels with a Label and TextBox for all Harddisks found over the Binding.
Therefore my XAML looks like:
<DockPanel Grid.Row="1" HorizontalAlignment="Stretch" Margin="5">
<ItemsControl ItemsSource="{Binding Harddisks}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel DockPanel.Dock="Right" HorizontalAlignment="Right" Margin="2.5,0,0,0">
<Label Content="{Binding Path=Label}" />
<TextBox Text="{Binding Path=GB_Free}" Width="100" IsReadOnly="True"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
It should be four Labels and TextBoxes, but only the first Label and TextBox are shown.
Why?
Your items in your ItemsControl are not actually direct children of the DockPanel. You need to change the ItemsControl to specify that the DockPanel is the Panel. The following will cause the ItemsControl to create a DockPanel and place all the items inside it (rather than the StackPanel that ItemsControl uses by default).
More Info: MSDN: ItemsControl.ItemsPanel Property
<ItemsControl ItemsSource="{Binding Harddisks}">
<ItemsControl.ItemsPanel>
<DockPanel Grid.Row="1" HorizontalAlignment="Stretch" Margin="5" />
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel DockPanel.Dock="Right" HorizontalAlignment="Right" Margin="2.5,0,0,0">
<Label Content="{Binding Path=Label}" />
<TextBox Text="{Binding Path=GB_Free}" Width="100" IsReadOnly="True"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

Binding data to the Listbox where ListBox has textblocks

<ListBox Height="498" Margin="2,0,0,0" Name="listBox1" Width="879" ItemsSource="{Binding}" >
<ListBoxItem >
<StackPanel Width="418" Orientation="Horizontal">
<TextBlock Name="MedicineName" Text="Alamoxy"
FontWeight="Bold" FontSize="18"
Margin="5" Width="205" >
</TextBlock>
<TextBlock Name="ListBoxLetter" Text="Amoksilin"
FontSize="18" Margin="0" Width="255" Height="23">
</TextBlock>
</StackPanel>
</ListBoxItem>
</ListBox>
I want to bind data to the listbox.
Textblock will show seprate fields. How i can do it?
please Help me about this/
Use an ItemTemplate to make it look something like this.
<ListBox Width="400" Margin="10" ItemsSource="{Binding myItems}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=MedicineName}" />
<TextBlock Text="{Binding Path=ListBoxLetter}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

MVVM WPF Creating Child Elements

I have a Customer object which has a List of Orders. Now, using MVVM pattern I am displaying a list of customers which is part of the CustomerOrderViewModel and "CustomerOrderView". The customers are shown using a listbox as implemented below:
<ListBox BorderThickness="0" Grid.Column="0" Grid.Row="0" ItemsSource="{Binding Path=Customers}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<view:CustomerView />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Now I also need to display the orders but I need to display it outside the ListBox. Like this:
<StackPanel Grid.Column="1" Grid.Row="0" Margin="10">
<ItemsControl ItemsSource="{Binding Path=Orders}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
This does not work because There is no property on CustomerOrderViewModel for Orders. The Orders is a collection on the Customer object. How can I achieve it?
Here is the updated example:
<ListBox BorderThickness="0" Grid.Column="0" Grid.Row="0" ItemsSource="{Binding Path=Customers}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<view:CustomerView />
<StackPanel Margin="20">
<ItemsControl ItemsSource="{Binding Path=Orders}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<view:OrderView />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I don't want to display the orders for all the customers. I just want to display the order of the currently selected customer.
You could use a master-detail binding.
I would suggest you to add an additional List to your window and bind its DataContext to the currently selected customer in your ListBox. It will be something like that:
<ListBox BorderThickness="0" Grid.Column="0" Grid.Row="0"
ItemsSource="{Binding Path=Customers}"
x:Name="CustomerList">
<ListBox.ItemTemplate>
<DataTemplate>
<view:CustomerView />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<ListBox Grid.Column="1" Grid.Row="0" DataContext="{Binding ElementName=CustomersList, Path=SelectedItem}">
<ListBox.ItemTemplate>
<DataTemplate>
<view:Order DataContext="{Binding Path=Orders}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

Resources