Aligment of Items in nested ItemsControls - c#

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.

Related

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>

Listbox: Change list item or each row height dynamically

I am working on Windows Phone 8, i have a Listbox with 4 items in it.
I want to change list item or each row height dynamically.
How to achieve this ?
Below is my code:
<ListBox Name="TopicListbox"
ItemTemplate="{StaticResource TitleDataTemplate}"
HorizontalAlignment="Stretch"
SelectionChanged="TopicListboxSelectionChanged">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
<DataTemplate x:Key="TitleDataTemplate">
<Grid MinHeight="90"
HorizontalAlignment="Stretch"
VerticalAlignment="Center">
</Grid>
</DataTemplate>
A good way to keep your items synchronized in height is to use a Grid with a ShareSizedScope :
<ListBox Name="TopicListbox"
ItemTemplate="{StaticResource TitleDataTemplate}"
HorizontalAlignment="Stretch"
SelectionChanged="TopicListboxSelectionChanged"
Grid.IsSharedSizeScope="True">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
<DataTemplate x:Key="TitleDataTemplate">
<Grid MinHeight="90"
HorizontalAlignment="Stretch"
VerticalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" SharedSizeGroup="A" />
</Grid.RowDefinitions>
<!-- Your template here -->
</Grid>
</DataTemplate>
Notice the add of Grid.IsSharedSizeScope="True" and of a RowDefinition with a SharedSizeGroup
This will allow your items to all keep the same height as they share a height group

ScrollViewer disappear automatically in WPF

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));
}
}

Use Binding for ElementName

I was unable to find a solution for this problem:
I am creating my own table with ItemControls. To resize the columns I'd like to bind the Width-property of one cell to the corresponding ActualWidth-property of the column.
I tried the following, but it is not working:
<StackPanel Orientation="Vertical">
<Border BorderBrush="Black" BorderThickness="1">
<ItemsControl ItemsSource="{Binding Data.Columns}" Margin="26,1,1,1">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<!-- here i set the name of the column (Code) -->
<Border BorderBrush="Black" BorderThickness="1,0,0,0" Width="100" x:Name="{Binding Code}">
<TextBlock Text="{Binding Header}" />
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Border>
<ItemsControl ItemsSource="{Binding Data.Rows}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Black" BorderThickness="1,0,1,1">
<StackPanel Orientation="Horizontal" Margin="1">
<Grid Width="25">
<General:SeverityIconControl Severity="{Binding Severity}" />
</Grid>
<ItemsControl ItemsSource="{Binding Values}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<!-- and here i'd like to bind to the ActualWidth of the corresponding column (Code)
but it is not working because ElementName={Binding LocalCode} does not work -->
<Border BorderBrush="Black" BorderThickness="1,0,0,0" Width="{Binding ActualWidth, ElementName={Binding LocalCode}}">
<TextBlock Text="{Binding Value}" />
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
Is there a way to solve this without changing the data source (unfortunately the data source cannot be edited)?
You can't bind x:Name (more info here) since it's only read when you call InitializeComponent() in the constructor.
Easiest way would be to add a DesiredWidth column to your Data object, and bind both widths to that (with a default value of 100).

How to bind data in an item control to stack panel?

I'm trying to create a custom ListBox. That receives a list with three properties:
SubjectName
Problems
AverageScore
The property Problems is another list which contains several Problem class. This is the data template I'm creating.
<DataTemplate x:Key="SubjectDataTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<StackPanel Margin="5">
<StackPanel Orientation="Horizontal" TextBlock.FontWeight="Bold" >
<TextBlock Text="{Binding Path=ProblemNumber, FallbackValue=ProblemNumber}" />
<TextBlock Text="{Binding Path=SubjectName, FallbackValue=SubjectName}" Padding="3,0,0,0"/>
</StackPanel>
<TextBlock Text="{Binding Path=AverageScore, FallbackValue=AverageScore}" />
<ItemsControl ItemsSource="{Binding Problems}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<StackPanel Background="Aqua" Orientation="Vertical" Margin="5">
<Rectangle Fill="Red" Height="20" Width="20" />
</StackPanel>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
<!--<TextBlock Text="{Binding Path=Role, FallbackValue=Role}" />-->
</StackPanel>
</Grid>
</DataTemplate>
But I've got a problem trying to show Problems data. I'm trying to show each element from Problems list in a stack panel with ortientation horizontal, but I get each stack panel separated.
I need to put the red rectangles inside the stack control. For example, the ten rectangles from Times Tables should be in one only stack panel.
UPDATE 1:
Something like this:
According to the graph, the first stack panel (background aqua) must contain 10 red rectangles.
UPDATE 2:
I'm verifying showing the data from problem in a textBlock and it works:
<ItemsControl ItemsSource="{Binding Problems}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding IsCorrect}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" Background="Gainsboro" Margin="5" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
You need to use nested ItemsControls - One for the Vertical list and one for the Horizontal List.
<ItemsControl ItemsSource="{Binding Problems}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding Problems}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Rectangle Height="20" Width="20" Margin="1,0">
<Rectangle.Style>
<Style TargetType="{x:Type Rectangle}">
<Setter Property="Fill" Value="Red" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsCorrect}" Value="True">
<Setter Property="Fill" Value="Blue" />
</DataTrigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
</Rectangle>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Background="Aqua" Margin="5" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
In your ItemsControl.ItemsPanel make the StackPanel orientation Horizoantal
Is this what you are looking for?
UPDATED:
<DataTemplate x:Key="SubjectDataTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<StackPanel Margin="5">
<StackPanel Orientation="Horizontal" TextBlock.FontWeight="Bold" >
<TextBlock Text="{Binding Path=ProblemNumber, FallbackValue=ProblemNumber}" />
<TextBlock Text="{Binding Path=SubjectName, FallbackValue=SubjectName}" Padding="3,0,0,0"/>
</StackPanel>
<TextBlock Text="{Binding Path=AverageScore, FallbackValue=AverageScore}" />
<ItemsControl ItemsSource="{Binding Problems}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<Rectangle Fill="Red" Height="20" Width="20" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Background="Aqua" Orientation="Horizontal" Margin="5"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</StackPanel>
</Grid>
</DataTemplate>

Categories

Resources