ListBox Child Count is 0 - silverlight

I'm trying to translate a control I wrote in WPF into Silverlight for Windows Phone. I've learned a lot and tweaked it quite a bit with improvements made to both versions, but I just can't seem to get the ScrollViewer out of a ListBox in the Silverlight version. It seemed pretty simple from the outset:
ScrollViewer s = VisualTreeHelper.GetChild(List, 0) as ScrollViewer;
However, when I reach this line, I get an IndexOutOfRangeException-- apparently, according to VisualTreeHelper, my ListBox has no visual children.
Since I get the feeling this is a special case, here's my XAML declaration of the ListBox:
<ListBox x:Name="List" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
ItemsSource="{Binding ItemsSource, ElementName=SnapListControl}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListBox.Style>
<Style TargetType="ListBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBox">
<ScrollViewer HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden">
<VirtualizingStackPanel Orientation="Horizontal" IsItemsHost="True"
Margin="{Binding ActualWidth, ElementName=LayoutRoot, Converter={StaticResource Hc}}">
</VirtualizingStackPanel>
</ScrollViewer>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.Style>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="RenderTransformOrigin">
<Setter.Value>
<Point X="0.5" Y="0.5"/>
</Setter.Value>
</Setter>
<Setter Property="Padding" Value="0"/>
<!--<Setter Property="ContentTemplate" Value="{Binding ItemContentTemplate, ElementName=SnapListControl}"/>-->
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
I had to comment out the ContentTemplate binding because apparently that's a readonly property in Silverlight? I'll have to investigate that more when I finish clearing this up.
I can't find much from googling this, most other people seem to use the method above to some success. It certainly works in WPF.

If your objective is simply to hide the ScrollViewer, you are already half way there. You simply need to use the following attached properties on your ListBox
<ListBox ScrollViewer.VerticalScrollBarVisibility="Hidden"
ScrollViewer.HorizontalScrollBarVisibility="Hidden" >
...
As for your other problems:
The ControlTemplate is not being applied because your ScrollViewer does not have a name. It must be named "ScrollViewer".
You cannot explicitly set your ItemsPanel in the ControlTemplate either. Instead, you must provide an ItemsPresenter, and then set the ItemsPanel property of the ListBox.
To set the DataTemplate for your content, you must set the ItemTemplate property on the ListBox.
<ListBox Height="100" Margin="200,195,156,0"
VerticalAlignment="Top"
ScrollViewer.VerticalScrollBarVisibility="Hidden"
ScrollViewer.HorizontalScrollBarVisibility="Hidden"
ItemContainerStyle="{StaticResource ListBoxItemStyle1}">
<ListBox.Style>
<Style TargetType="ListBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBox">
<ScrollViewer x:Name="ScrollViewer" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Foreground="{TemplateBinding Foreground}" Padding="{TemplateBinding Padding}">
<ItemsPresenter/>
</ScrollViewer>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.Style>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal"
Margin="{Binding ActualWidth, ElementName=LayoutRoot, Converter={StaticResource Hc}}">
</VirtualizingStackPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Border Width="100" Height="100" Background="White">
...
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

Related

Button Style performance hit

I have a usecase to show nearly 10000 items in a WPF usercontrol. I am using ItemsControl and each item is represented by a button (items a simple clickable text). I have defined a style for button in usercontrol resources.
Things work fine till I have more than 5000 items in my list then UI paint starts to slow down- 10000 items takes nearly 3+ minutes to be displayed.
If I move the style from resources to Button.Style then also it take 2.5 mins to displays the items.
If I remove the style completely, I see no noticeable delay.The only reason to use Button style is to give its ContentPresenter's Border (named as Chrome in below code) the same background as button, which is otherwise Gray.
Please let me know how can I use styles efficiently without incurring a Performance hit or how can I paint the ContentPresenter Border's Background as same color as Button (transparent would work somehow).
Here is the code sample:
<UserControl.Resources>
<Style x:Key="ButtonStyle" TargetType="{x:Type Button}" BasedOn="{x:Null}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="Chrome" Background="{TemplateBinding Property=Background}">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
<ContentPresenter.Resources>
<Style TargetType="{x:Type TextBlock}" BasedOn="{x:Null}">
<Setter Property="FontSize" Value="{Binding FontSize, RelativeSource={RelativeSource AncestorType={x:Type Button}}}"/>
</Style>
</ContentPresenter.Resources>
</ContentPresenter>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Grid Name="Grid1" Margin="5,5,5,5">
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" Margin="5,0,0,0">
<Border Name="Border1" Margin="2,2,2,2" BorderBrush="Gray" BorderThickness="2">
<ItemsControl Name="ItemsControl1" ItemsSource="{Binding LargeItems}" FocusVisualStyle="{x:Null}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="{Binding Columns}" Rows="{Binding Rows}"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Name="Border1" Background="{Binding BorderBkg}"
BorderThickness="1" Padding="{Binding PaddingVal}">
<Button Name="MyButton" Content="{Binding Label}"
Background="{Binding Background}"
Foreground="{Binding Foreground}"
BorderThickness="0"
BorderBrush="Transparent"
Margin="0"
Style="{StaticResource ButtonStyle}"
IsEnabled="{Binding IsButtonEnabled}"
Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}}, Path=DataContext.ButtonAction}"
CommandParameter="{Binding}">
</Button>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Border>
</ScrollViewer>
</Grid>
Thanks,
RDV
It seems that there is no data virtualization implemented in your ItemControl. You can implement the virtualization by adding
VirtualizingPanel.IsVirtualizing="True" VirtualizingPanel.VirtualizationMode="Recycling"
in your ItemsControl and see the performance difference.

ItemsControl is preventing item content from expanding to fill its container

I am creating a WPF custom control that inherits from ItemsControl. In the ControlTemplate of my control I have an ItemsPresenter. The problem is that I need to be able to get content in the items presenter to fill the entire content area. In the code below I have a simplified example of the broken code and also what I am trying to accomplish. BTW setting HorizontalAlignment and VerticalAlignment to Stretch causes the content expand horizontally but not vertically.
<Window x:Class="yada"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="768" Width="1024">
<Grid>
<Grid.Resources>
<Style TargetType="Border" x:Key="stepBorder">
<Setter Property="Background" Value="CadetBlue"></Setter>
<Setter Property="BorderBrush" Value="Green" ></Setter>
<Setter Property="BorderThickness" Value="2"></Setter>
<Setter Property="Padding" Value="25"></Setter>
</Style>
</Grid.Resources>
<TabControl Margin="0,20,0,0">
<TabItem Header="Broken">
<Border>
<ItemsControl>
<ItemsControl.Items>
<Control>
<Control.Template>
<ControlTemplate>
<Border Style="{StaticResource stepBorder}">
<TextBlock Text="Border fills small region near the top"></TextBlock>
</Border>
</ControlTemplate>
</Control.Template>
</Control>
</ItemsControl.Items>
</ItemsControl>
</Border>
</TabItem>
<TabItem Header="Works">
<Border>
<Control>
<Control.Template>
<ControlTemplate>
<Border Style="{StaticResource stepBorder}" >
<TextBlock Text="Border fills entire control"></TextBlock>
</Border>
</ControlTemplate>
</Control.Template>
</Control>
</Border>
</TabItem>
</TabControl>
</Grid>
</Window>
Here is some code from my control. I cant include it all, there is too much. I think this is the relevant part however:
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:Wizard}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" x:Name="ContentRow" />
<RowDefinition Height="{Binding ElementName= NavButtonPanel,Path=ActualHeight}"></RowDefinition>
</Grid.RowDefinitions>
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" x:Name="ContentScrollViewer" MaxHeight="{Binding ElementName=ContentRowHeight, Path=ActualHeight}">
<ItemsPresenter
x:Name="Presenter"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}">
</ItemsPresenter>
</ScrollViewer>
<Border Style="{TemplateBinding NavButtonPanelStyle}" Grid.Row="1" x:Name="NavButtonPanel">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" >
</StackPanel>
</Border>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate></DataTemplate>
</Setter.Value>
</Setter>
As usual, just posting on SO gets me halfway to my answer.
It turns out the ItemsControl is using an evil stackpanel as a container for items. Fortunately there is a top-secret property called ItemsPanel that lets you change this. Just set it to a grid as shown below and you are in business.
In my case I am writing a custom control that inherits from ItemsControl so in the Style I add this property setter:
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<Grid></Grid>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>

creating Icon View mode for ListView WPF

I'm Trying to change listView GridView to IconView, as you see in the screenshot, each item is taking a row.
Style XAML
<UserControl.Resources>
<Style x:Key="FileItemStyle" TargetType="{x:Type ListViewItem}">
<Setter Property="Width" Value="50"/>
<Setter Property="Margin" Value="5,5,5,5"/>
<Setter Property="Padding" Value="0,0,0,0"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<Grid HorizontalAlignment="Left" VerticalAlignment="Top" Height="50" Width="50">
<Border x:Name="border" BorderBrush="{x:Null}" BorderThickness="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" CornerRadius="2.5"/>
<StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ContentPresenter />
</StackPanel>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
ListView XAML
<ListView ItemContainerStyle="{DynamicResource FileItemStyle}" HorizontalAlignment="Left" Height="194.667" Margin="11,77.666,0,0" VerticalAlignment="Top" Width="368.667" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.CanContentScroll="True" UseLayoutRounding="False">
<ListView.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Left" Height="50">
<Border x:Name="border" BorderBrush="{x:Null}" BorderThickness="1" HorizontalAlignment="Stretch" Height="50" VerticalAlignment="Stretch" Width="50" CornerRadius="2.5"/>
<StackPanel>
<Image x:Name="Img" Source="BtnImg/Computer.png" Stretch="None" Margin="9,0,9,0" Width="32" Height="32"/>
<TextBlock x:Name="PCName" Margin="0" TextWrapping="Wrap" Height="18" HorizontalAlignment="Stretch" TextAlignment="Center"><Run Text="{Binding Content}"/></TextBlock>
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
<ListBoxItem Content="ddd"/> <!--**-->
<ListViewItem Content="zczxcz"/>
</ListView>
I've tried to use MDSN example : How to: Create a Custom View Mode for a ListView and modify it to get what I need, but it didn't work with me, I actually couldn't understand the example clearly, anyone can Simplify how can I create a View mode? Do I have to create an overrided ViewBase class?
Thanks in advance
Using the same exact Code Behind as My Answer to your previous question:
<Style x:Key="FileItemStyle" TargetType="{x:Type ListViewItem}">
<Setter Property="Margin" Value="5,5,5,5"/>
<Setter Property="Padding" Value="0,0,0,0"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<Grid HorizontalAlignment="Left" VerticalAlignment="Top" Height="50" >
<Border x:Name="border" BorderBrush="{x:Null}" BorderThickness="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" CornerRadius="2.5"/>
<StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ContentPresenter/>
</StackPanel>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Then:
<ListView ItemsSource="{Binding}" ScrollViewer.HorizontalScrollBarVisibility="Disabled"
SelectedItem="{Binding SelectedComputer, RelativeSource={RelativeSource AncestorType=Window}}"
ItemContainerStyle="{StaticResource FileItemStyle}">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<DockPanel>
<TextBlock DockPanel.Dock="Bottom" Text="{Binding Name}"/>
<Rectangle Height="32" Width="32" Fill="Blue"/>
</DockPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Result:
Remove the hardcoded Width and Heights
Replace the blue rectangle for your Image.
Add some Triggers in the ControlTemplate so that you get highlighting when IsSelected="True"
Simply change the ItemsPanel of any ItemsControl in order to define how items are laid out.
Using a WrapPanel, you get a layout similar to Windows Explorer, where items are placed horizontally until there is no more horizontal space and then another "row" is created. Run the example and resize the Window to see this.
Bottom line: NO, you don't need custom code to customize the UI in WPF. It can be done with the existing controls and some XAML. Please read the "Alternatives to Writing a New Control" section in MSDN: Control Authoring Overview

Relative Binding in RichTextBox to its Paragraph

I want to display a Line of Text via an ItemsControl beside a RichTextBox. Therefore I created this ControlTemplate:
<RichTextBox Margin="5,0,5,0">
<RichTextBox.Resources>
<Style TargetType="{x:Type Paragraph}">
<Setter Property="Margin" Value="5,0,5,0"/>
<Setter Property="LineHeight" Value="30"/>
<Setter Property="LineStackingStrategy" Value="BlockLineHeight"/>
</Style>
</RichTextBox.Resources>
<RichTextBox.Template>
<ControlTemplate>
<StackPanel Orientation="Horizontal">
<ItemsControl ItemsSource="{Binding Lines}" Margin="5,0,5,0">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ToggleButton Content="{Binding}" Height="{Binding BIND_ME_TO_LineHeigh_OF_PARAGRAPH" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Border Name="Border" CornerRadius="2" Padding="2" Background="White" BorderBrush="Black" BorderThickness="0" >
<ScrollViewer Margin="0" x:Name="PART_ContentHost"/>
</Border>
</StackPanel>
</ControlTemplate>
</RichTextBox.Template>
To make the Items in the ItemsControl the same size as the paragraph's line I want to bind the ToggleButton's height to the LineHeight of the Paragraph which I defined in the Style for the Pararaph ( ). How can I do that?
Thanks

Bind image in templated ListBox to ViewModel property

TL;DR - I had a binding error. Tired eyes miss things.
I have implemented a multi-select CheckBox list using a ListBox as the container. Now, beside each checkbox in the list I want to display an image whose visbility is bound to a ViewModel property, but I'm having difficulty doing this.
My styles are:
<Grid.Resources>
<Style x:Key="ListBoxCheckStyle" TargetType="ListBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBox">
<ItemsPresenter HorizontalAlignment="Left" VerticalAlignment="Top"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<ItemsPanelTemplate x:Key="ListBoxCheckStyleItemsPanelTemplate">
<StackPanel />
</ItemsPanelTemplate>
<Style x:Key="ListBoxItemCheckStyle" TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<StackPanel Orientation="Horizontal">
<ChimeControls:CheckBox
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Margin="0,0,10,0"
IsChecked="{Binding IsSelected, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"/>
<Image
Width="16"
Height="16"
VerticalAlignment="Center"
Source="{StaticResource OccurredStatusTypeImageSource}"
Visibility="{Binding HasConsentCondition, Converter={StaticResource BoolToVisibilityConverter}, FallbackValue=Collapsed}"
HorizontalAlignment="Right"
Margin="10,0,10,0" />
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
My Listbox is defined as:
<ListBox
x:Name="objectivesListBox"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Style="{StaticResource ListBoxCheckStyle}"
ItemsPanel="{StaticResource ListBoxCheckStyleItemsPanelTemplate}"
ItemContainerStyle="{StaticResource ListBoxItemCheckStyle}"
ItemsSource="{Binding ObjectivesList}"
DisplayMemberPath="mgt_plan_obj_name"
AttachedProperties:ListBoxSelectedItems.Items="{Binding SelectedObjectives, Mode=TwoWay}"
SelectionMode="Multiple"/>
My image never displays though, and the getter of the property the Visibility is bound to is never called. What am I missing?
As suggested by nemesv, I checked my output window again and there was my binding error.

Resources