ScrollViewer disappear automatically in WPF - c#

i have an items control that is bound to an observable collection of videos.I added a vertical scroll bar but but it disappear after the page is loaded.
<ItemsControl x:Name="_imageList" ScrollViewer.CanContentScroll="True" HorizontalAlignment="Right" Margin="-1,0" Width="460" >
<ItemsControl.Template>
<ControlTemplate>
<ScrollViewer x:Name="ScrollViewer" Padding="{TemplateBinding Padding}" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
<ItemsPresenter />
</ScrollViewer>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="4" Rows="3"/>
<!--<StackPanel Orientation="Horizontal"/>-->
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Click="btn_Clicked" Margin="9,9,9,9" BorderThickness="0" Style="{StaticResource {x:Static ToolBar.ButtonStyleKey}}">
<Image x:Name="image" Source="{Binding thumbnail}" ClipToBounds="True"/>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
This is code behind of my page:
public void Images()
{
var images = new ObservableCollection<Video>();
var wcf = new ServiceReferenceVideo.VideoServiceClient();
link_thumb = new Dictionary<string, string>();
foreach (var item in wcf.GetAllVideos())
{
images.Add(item);
}
_imageList.ItemsSource = images;
}

Try putting the Scrollviewer outside the ItemsControl. Something like...
<ScrollViewer>
<ItemsControl>
</ItemsControl>
</ScrollViewer>

This wont work because your UniformGrid automatically adopts to the available size. Try set a fixed Width or MinWidth like 300 for the buttons in your DataTemplate
Here is a working example:
XAML:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
Width="525"
Height="350">
<Grid>
<ItemsControl x:Name="Items">
<ItemsControl.Template>
<ControlTemplate TargetType="ItemsControl">
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<ItemsPresenter />
</ScrollViewer>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="4"
IsItemsHost="True"
Rows="3" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button MinWidth="200"
MinHeight="200"
Margin="9"
Content="{Binding }" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Window>
Code Behind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.Items.ItemsSource = new List<int>(Enumerable.Range(0,100));
}
}

Related

WPF VirtualizingStackPanel not redrawing on horizontal resize

I have an ItemsControl with a vertical VirtualizingStackPanel that has items with wrapping TextBlocks. Horizontally resizing the parent container fails to re-draw the elements below a certain size, only redrawing once you've scrolled up/down. However above a certain size the redrawing happens correctly. This only seems to be an issue when Virtualization is enabled.
I've created a simple example which demonstrates the issue here...
<Window x:Class="WpfTesting.MainWindow"
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:WpfTesting"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance local:MainWindow}"
Title="MainWindow" Height="450" Width="800">
<ItemsControl ItemsSource="{Binding LongStrings}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Margin="5"
Padding="5"
Background="Gray"
BorderBrush="Black"
BorderThickness="2"
CornerRadius="8">
<TextBlock TextWrapping="Wrap"
Text="{Binding}"/>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.Template>
<ControlTemplate TargetType="ItemsControl">
<ScrollViewer CanContentScroll="True"
Focusable="False">
<ItemsPresenter />
</ScrollViewer>
</ControlTemplate>
</ItemsControl.Template>
</ItemsControl>
</Window>
CodeBehind...
public partial class MainWindow : Window
{
public List<string> LongStrings { get; }
public MainWindow()
{
InitializeComponent();
DataContext = this;
LongStrings = Enumerable.Range(1, 20)
.Select(_ => new string(Enumerable.Repeat('a', 1000).ToArray()))
.ToList();
}
}
I feel a little silly that the solution is so simple but you can fix it relatively easily by binding the Width property of the Item you're displaying to the ActualWidth property of the VirtualizingStackPanel.
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Width="{Binding ActualWidth, ElementName=StackPanel}">
<Border Margin="5"
Padding="5"
Background="Gray"
BorderBrush="Black"
BorderThickness="2"
CornerRadius="8">
<TextBlock TextWrapping="Wrap"
Text="{Binding}"/>
</Border>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel x:Name="StackPanel"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
Frankly I'm convinced that the rendering behaviour of the VirtualizingStackPanel is a bug given just how odd it is.

WPF - ScrollViewer returns to start position

I have a table with cells, where values can be inserted. Table is generated dynamically, based on data. Table size is limited by the grid, where it is located. If data is too much, then appears a horizontal scroll bar.
This is implemented with ItemsControl in the ScrollViewer.
<ScrollViewer
VerticalScrollBarVisibility="Hidden" HorizontalScrollBarVisibility="Auto">
<ItemsControl ItemsSource="{Binding Data}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border>
<ItemsControl ItemsSource="{Binding Value}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition SharedSizeGroup="SomeCellRowSize"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="SomeCellRowSize"/>
</Grid.ColumnDefinitions>
<TextBox
Text="{Binding Value.TotalTime}"
HorizontalContentAlignment="Right" BorderThickness="0" Margin="1,1,0,0"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
The problem happens, when we scroll the table to the right and select some cell (TextBox). If we do this, then ScrollViewer will return to the most left position.
It's better to have an integrated ScrollViewer inside the ItemsPanel itself than wrapping a ScrollViewer around it. From my experience, you tend to have more issues. Update your Template to have the ScrollViewer instead.
<ItemsControl ItemsSource="{Binding Data}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.Template>
<ControlTemplate>
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Disabled">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}"/>
</ScrollViewer>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border>
<ItemsControl ItemsSource="{Binding Value}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition SharedSizeGroup="SomeCellRowSize"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="SomeCellRowSize"/>
</Grid.ColumnDefinitions>
<TextBox
Text="{Binding Value.TotalTime}"
HorizontalContentAlignment="Right" BorderThickness="0" Margin="1,1,0,0"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

Aligment of Items in nested ItemsControls

I have two ItemsControls nested within a single ItemsControl. Each are placed next to each other in Grid Columns with horizontally oriented StackPanel ItemsPanelTemplates so their contents are layer out horizontally.
While I want the two ItemsControls to occupy the full width of the parent, (50:50), I want the items within them to be right, and left aligned respectively... so they both are centred, something like (excuse my attempt at ASCII art):
| LH ItemsControl | RH ItemsControl |
| [][][][]|[][][] |
Here's my code so far, I have been tweaking the HorizontalAlignment attributes but if I get them to occupy the centre, then the two StackPanels don't fill the full width of the parent.
<ItemsControl ItemsSource="{Binding Things}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ItemsControl Grid.Column="0" ItemsSource="{Binding LeftThings}" HorizontalAlignment="Stretch">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" Background="LightPink" HorizontalAlignment="Stretch" Height="37"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
<ItemsControl Grid.Column="1" ItemsSource="{Binding RightThings}" HorizontalAlignment="Stretch">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" Background="LightBlue" HorizontalAlignment="Stretch" Height="37"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
Any ideas?
Rich
Setting the Background property on the ItemsControl rather than the StackPanel and setting Orientation to Left and Right respectively on the StackPanel gave me the effect I was after:
<ItemsControl ItemsSource="{Binding Things}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ItemsControl Grid.Column="0" ItemsSource="{Binding LeftThings}" HorizontalAlignment="Stretch" Background="LightPink">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Height="37"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
<ItemsControl Grid.Column="1" ItemsSource="{Binding RightThings}" HorizontalAlignment="Stretch" Background="LightBlue">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" Height="37"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
Use FlowDirection=RightToLeft on left stackpanel, and FlowDirection=LeftToRight in DataTemplate control. I made a sample. Below code can be used as is :
MainWindow.xaml
<Window x:Class="WpfItemsControl.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="407.895" Width="884.211">
<Grid>
<ItemsControl ItemsSource="{Binding Names}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ItemsControl ItemsSource="{Binding ItemsSource, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ItemsControl}}" Grid.Column="0">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" Background="Red" HorizontalAlignment="Stretch" FlowDirection="RightToLeft">
</StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Background="DarkGoldenrod" FontSize="25" FontWeight="Bold" Foreground="Gray" Text="{Binding}" FlowDirection="LeftToRight"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<ItemsControl ItemsSource="{Binding ItemsSource, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ItemsControl}}" Grid.Column="1">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" Background="Red" HorizontalAlignment="Stretch" FlowDirection="LeftToRight">
</StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Background="DarkGoldenrod" FontSize="25" FontWeight="Bold" Foreground="Gray" Text="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Window>
MainWindow.xaml.cs
namespace WpfItemsControl
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
try
{
InitializeComponent();
this.DataContext = new DataStore();
}
catch (Exception ex)
{
Debug.WriteLine(ex.InnerException.Message);
}
}
}
public class DataStore
{
public List<string> Names { get; set; }
public DataStore()
{
Names = new List<string>();
Names.Add(">");
Names.Add(">");
Names.Add(">");
Names.Add(">");
Names.Add(">");
}
}
}
This code puts both side items in center, and stretches both stackpanels.

ListView with dynamic raws and columns that stays propetinal aytomatically

I am developing a WPF application.
have a list of user controls
<Grid >
<ListView ItemsSource="{Binding MyList}" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" >
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Vertical" ItemWidth="{Binding (ListView.View).ItemWidth, RelativeSource={RelativeSource AncestorType=ListView}}"
MinWidth="{Binding ItemWidth, RelativeSource={RelativeSource Self}}"
ItemHeight="{Binding (ListView.View).ItemHeight, RelativeSource={RelativeSource AncestorType=ListView}}"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate >
<DataTemplate >
<Views:MyUserControl Height="auto" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" SnapsToDevicePixels="True"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
And MyUserControl has another list of user controls "DetailUserControl":
<UserControl x:Class="MyUserControl"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300" >
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="45" />
<RowDefinition />
</Grid.RowDefinitions>
<Border Grid.RowSpan="2" >
<StackPanel VerticalAlignment="Top" Orientation="Horizontal" HorizontalAlignment="Center" >
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" Margin="10" Text="{Binding Title}" />
</StackPanel>
</Border>
<Border Grid.Row="1" Style="{StaticResource SummaryInnerFill}" >
<ItemsControl ItemsSource="{Binding DetailUserControls}" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Border>
</Grid>
I used wrap panel to make all the usercontrols to be orderd from left to right one after the other.
I want the layout to be optimized and use as much as it can from the first line, and only then it will move to the second line.
here is an example (sorry for my drawing skills :) )
I have the following layout:
if I change the order inside the tiles I can have the following layout (that contains the same tiles but don't waste space an is much more organized):
Is there a panel I can use that will take care of it?
You can make use of Uniform Control Grid. You can specify Rows and Columns Properties. Controls are added to the grid in the order that they are declared.Its child controls are organised into a tabular structure of rows and columns. Unlike the Grid control, you don't have fine-grained control of the layout.
Example,
<UniformGrid Name="uniformGrid1"
Rows="2"
Columns="3">
<Button Content="blah"
Margin="2" />
<Button Content="blah1"
Margin="2" />
<Button Content="blah2"
Margin="2" />
</UniformGrid>
UniformGrid

How do I dynamically size a GridView Item?

I have a Grid View that is used to display "tags" which is a list of strings that are dynamic in size. Using the following code:
<GridView ItemsSource="{Binding Tags}"
ItemTemplate="{StaticResource TagTemplate}"
VerticalAlignment="Bottom"
Grid.RowSpan="2"
SelectionMode="None"
/>
I use the following Template for the items:
<DataTemplate x:Name="TagTemplate">
<Border BorderBrush="Gray" BorderThickness="1" Opacity="75">
<TextBlock Text="{Binding}"/>
</Border>
</DataTemplate>
When added to the Grid, the size of each of the items are the same size as the first:
How do I dynamically size the items within the GridView?
So something like;
<ScrollViewer>
<ItemsControl ItemsSource="{Binding Tags}">
<!-- ItemsPanelTemplate -->
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
<!-- Or use WrapPanel depending on its display -->
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<!-- ItemContainerStyle -->
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Gray" BorderThickness="1" Opacity="75" Padding="3" Margin="3,0">
<TextBlock Text="{Binding}"/>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>

Categories

Resources