I followed this small "tutorial" on how to add a scrollbar to an ItemsControl, and it works in Designer view, but not when I compile and execute the program (only the first few items show up, and no scrollbar to view more - even when VerticalScrollbarVisibility is set to "Visible" instead of "Auto").
Any idea on how to solve this?
This is the code I use to show my items (normally I work with Databinding, but to see the items in my Designer I added them manually):
<ItemsControl x:Name="itemCtrl" Style="{DynamicResource UsersControlStyle}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Top">
</StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<uc:UcSpeler />
<uc:UcSpeler />
<uc:UcSpeler />
<uc:UcSpeler />
<uc:UcSpeler />
</ItemsControl>
And this is my Template:
<Style x:Key="UsersControlStyle" TargetType="{x:Type ItemsControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ItemsControl}">
<Border SnapsToDevicePixels="true" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}">
<ScrollViewer VerticalScrollBarVisibility="Visible">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
To get a scrollbar for an ItemsControl, you can host it in a ScrollViewer like this:
<ScrollViewer VerticalScrollBarVisibility="Auto">
<ItemsControl>
<uc:UcSpeler />
<uc:UcSpeler />
<uc:UcSpeler />
<uc:UcSpeler />
<uc:UcSpeler />
</ItemsControl>
</ScrollViewer>
You have to modify the control template instead of ItemsPanelTemplate:
<ItemsControl >
<ItemsControl.Template>
<ControlTemplate>
<ScrollViewer x:Name="ScrollViewer" Padding="{TemplateBinding Padding}">
<ItemsPresenter />
</ScrollViewer>
</ControlTemplate>
</ItemsControl.Template>
</ItemsControl>
Maybe, your code does not working because StackPanel has own scrolling functionality. Try to use StackPanel.CanVerticallyScroll property.
Put your ScrollViewer in a DockPanel and set the DockPanel MaxHeight property
[...]
<DockPanel MaxHeight="700">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<ItemsControl ItemSource ="{Binding ...}">
[...]
</ItemsControl>
</ScrollViewer>
</DockPanel>
[...]
Related
I am using WpfToolkit to draw a Pie chart,and I like to show my legend into two column due to my legend is to much,how can I solve it?
<chartingToolkit:Chart Height="auto" x:Name="PieChart2" Title="{Binding}"
VerticalAlignment="Top" Grid.Row="0" Grid.ColumnSpan="3" Margin="5" LegendTitle="Label" >
<chartingToolkit:PieSeries DependentValuePath="Value"
IndependentValuePath="Key" ItemsSource="{Binding}">
</chartingToolkit:PieSeries>
<charting:Chart.LegendStyle>
<Style TargetType="datavis:Legend">
<Setter Property="HorizontalAlignment" Value="Stretch"/>
</Style>
</charting:Chart.LegendStyle>
</chartingToolkit:Chart>
Thanks in advance!
As per your need , I have changed the ControlTemplate of the Legend a litte as shown below
<ControlTemplate x:Key="LegendControlTemplate1"
TargetType="{x:Type visualizationToolkit:Legend}">
<Border BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
Padding="2">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<visualizationToolkit:Title x:Name="HeaderContent"
ContentTemplate="{TemplateBinding HeaderTemplate}"
Content="{TemplateBinding Header}"
Grid.Row="0"
Style="{TemplateBinding TitleStyle}" />
<ScrollViewer BorderThickness="0"
IsTabStop="False"
Padding="0"
Grid.Row="1"
VerticalScrollBarVisibility="Auto">
<!--<ItemsPresenter x:Name="Items"
Margin="10,0,10,10" >
</ItemsPresenter>-->
<ItemsControl x:Name="Items"
Margin="10,0,10,10"
ItemsSource="{TemplateBinding ItemsSource}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="2" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</ScrollViewer>
</Grid>
</Border>
</ControlTemplate>
I am not sure whether this suites your requirement or not..Please mark it as answer if satisfied.
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.
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>
I have an own control which derives from itemscontrol with an own template. I am using a Canvas inside the itemscontrol as ItemsPanel. Why f.e. on resize of the window the items also can be outside of the itemscontrol?
Templates:
<Style TargetType="{x:Type local:Dashboard}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:Dashboard}">
<Grid>
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Style>
The items use this:
<Style TargetType="{x:Type local:Widget}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:Widget}">
<Grid Background="{TemplateBinding Background}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Border Grid.Row="0" BorderThickness="2" BorderBrush="Black" Background="WhiteSmoke"
x:Name="Part_Header">
<ContentPresenter ContentSource="Header"/>
</Border>
<Border Grid.Row="1" BorderThickness="2" BorderBrush="Black" Background="WhiteSmoke">
<Grid>
<ContentPresenter />
<ResizeGrip x:Name="Part_Resize"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Cursor="SizeNWSE" />
</Grid>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Depending on your alignment and margin settings, resizing a parent can cause children to move outside of a parent's boundaries. The easiest way I've found to check this is to load Blend and resize the parent, watching how contained controls move. By tweaking the anchors in Blend (which changes alignments and margins), you should be able to troubleshoot why they move.
I followed the instruction in this blog to add ScrollIntoView to ItemsControl.
But this makes the border invisible:
<ItemsControl BorderBrush="Black"
BorderThickness="3">
<ItemsControl.Template>
<ControlTemplate>
<ScrollViewer Padding="{TemplateBinding Padding}">
<ItemsPresenter />
</ScrollViewer>
</ControlTemplate>
</ItemsControl.Template>
<TextBlock Text="Test" />
<TextBlock Text="Test" />
<TextBlock Text="Test" />
</ItemsControl>
In order to display the border, I have to remove:
<ItemsControl.Template>
<ControlTemplate>
<ScrollViewer Padding="{TemplateBinding Padding}">
<ItemsPresenter />
</ScrollViewer>
</ControlTemplate>
</ItemsControl.Template>
But this way I won't be able to use the ScrollIntoView method.
Any ideas? Thanks
You need to include the border in the template.
<ControlTemplate>
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ScrollViewer Padding="{TemplateBinding Padding}">
<ItemsPresenter />
</ScrollViewer>
</Border>
</ControlTemplate>