I want to make a ListBox that arranges items horizontally. Each item should be a TextBox, and it should fill the list box vertically regardless how how much text is there. If you've used Tweetdeck, I'm aiming for a similar effect. Here's what I've got:
<ListBox
Background ="DarkGray"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollBarVisibility="Disabled"
ItemsSource="{Binding Path=Items}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<DockPanel IsItemsHost="True"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Gray" BorderThickness="2" CornerRadius="5" Margin="2,0,2,0">
<Grid Width="250">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBox
Grid.Row="0"
Grid.Column="0"
VerticalAlignment="Stretch"
Text="{Binding Path=Messages, Mode=OneWay}" />
</Grid>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
What happens is that the TextBox stubbornly fits the text in it, rather than stretching vertically. I've tried switching the Grid for a DockPanel, which didn't help. I could bind the TextBox's Height property, but that seems unpleasant.
Is there a trick to this that I've missed?
You need to set VerticalContentAlignment="Stretch" on your ListBox.
Related
I have a problem with an image stretching in a ListBox:
<ListBox x:Name="DeviceModelListBox"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
VirtualizingPanel.IsVirtualizing="True"
VirtualizingPanel.VirtualizationMode="Recycling"
BorderThickness="0"
ItemsSource="{Binding DeviceModels}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" Rows="1" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid x:Name="DeviceModelGrid"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Image Grid.Column="0"
Grid.Row="0"
Stretch="Uniform"
Source="pack://application:,,,/AppAssembly;component/Resource/Filename.png" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
My images are bigger than ListBox available space and I just want to stretch images to stop at Grid's row height and column width, but every Image's stretch property value do nothing. How should I limit Image's size to available space in XAML? The same thing happens with a ViewBox.
I'm building a grid via WPF, and it works great. I need to add a row, or bar, or something to display above the grid, that will have several text items on it that will get populated by code. I've been tooling around, and I can't seem to figure out how to put another panel above my existing (and working) grid. This is my code:
<Window x:Class="GridWPF.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Board" SizeToContent="WidthAndHeight" Height="Auto" Width="Auto">
<Window.Resources>
<DataTemplate x:Key="DataTemplate_2">
<Button Content="{Binding}" Height="25" Width="25" Margin="0,0,0,0"/>
</DataTemplate>
<DataTemplate x:Key="DataTemplate_1">
<ItemsControl ItemsSource="{Binding}" ItemTemplate="{DynamicResource DataTemplate_2}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</DataTemplate>
</Window.Resources>
<Grid Name="GridBoard" ShowGridLines="True">
<ItemsControl x:Name="GridItems" ItemTemplate="{DynamicResource DataTemplate_1}"/>
</Grid>
</Window>
The GridItems gets populated by a jagged array, and displays fine. I just need to put a few text objects above it, be it boxes, or just a horizontal panel that fits the width of the grid.
May be the simplest option is to add a wrapper Grid and put your inner Grid in the second row. So, you will have the first row (row 0) to put anything you need there.
<Window x:Class="GridWPF.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Board" SizeToContent="WidthAndHeight" Height="Auto" Width="Auto">
<Window.Resources>
<DataTemplate x:Key="DataTemplate_2">
<Button Content="{Binding}" Height="25" Width="25" Margin="0,0,0,0"/>
</DataTemplate>
<DataTemplate x:Key="DataTemplate_1">
<ItemsControl ItemsSource="{Binding}" ItemTemplate="{DynamicResource DataTemplate_2}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid>
<!-- WHATEVER YOU NEED -->
</Grid>
<Grid Name="GridBoard" ShowGridLines="True" Grid.Row="1">
<ItemsControl x:Name="GridItems" ItemTemplate="{DynamicResource DataTemplate_1}"/>
</Grid>
</Grid>
There are a few ways to achieve it.
1 - you can add a row and columns to your grid definition:
<Grid.ColumnDefinitions>
<ColumnDefinition width="*" />
<ColumnDefinition width="*" />
<ColumnDefinition width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
Then you can just assign 'headers' to each column, like so:
<TextBlock ... Grid.Column="0" />
<TextBlock ... Grid.Column="1" />
<TextBlock ... Grid.Column="2" />
And place your ItemsControl in the second row:
<ItemsControl ... Grid.Row="1" Grid.ColumnSpan="3" />
A half-assed way that may or may not work in your case. No way of knowing without taking a look at the DataTemplate.
2 - StackPanel at the top, with margin applied to the ItemsControl
You can use a similar half-solution - set the top margin of your ItemsControl to a fixed value, like so:
<ItemsControl ... Margin="2,48,2,2" />
And add a StackPanel to your grid:
<StackPanel Height="48" VerticalAlignment="Top">
<TextBlock Text="First Header" Width="300" />
...
</StackPanel>
I'm sure you get the idea.
3 - Use a GridView -RECOMMENDED-
This would require you to change your ItemsControl to a ListView, though.
Here is a well-written tutorial on GridViews for WPF. Granted, it might not be what you're looking for, but again - without knowing what you're trying to present it's difficult to find best solution.
I don't know what you expect the output to look like, but you can nest your "GridBoard" Grid within another Grid. The new outer Grid defines two rows, whereby in the first row you can put your boxes or whatever you like. This could look like this for example:
<Window x:Class="GridWPF.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Board" SizeToContent="WidthAndHeight" Height="Auto" Width="Auto">
<Window.Resources>
<DataTemplate x:Key="DataTemplate_2">
<Button Content="{Binding}" Height="25" Width="25" Margin="0,0,0,0"/>
</DataTemplate>
<DataTemplate x:Key="DataTemplate_1">
<ItemsControl ItemsSource="{Binding}" ItemTemplate="{DynamicResource DataTemplate_2}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<TextBlock Text="Put something here ..." />
</Grid>
<Grid Grid.Row="1" Name="GridBoard" ShowGridLines="True">
<ItemsControl x:Name="GridItems" ItemTemplate="{DynamicResource DataTemplate_1}"/>
</Grid>
</Grid>
</Window>
Note that you could use any element for the content of the first row of your outer Grid. This depends on your actual needs. In this example I used another Grid which contains a single TextBlock.
When applying a itemsControl i found that logical scrolling (canContentScroll="true") no longer seems t be working.
With logical scrolling i mean viewing item per item when clicking for example 2 navigation buttons that moves the scrollviewer.
The content of the itemControl is as the following:
<Grid Height="70" Width="900">
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="LeftScrollRow2" Width="Auto"/>
<ColumnDefinition x:Name="HorizontalContentRow2" Width="*"/>
<ColumnDefinition x:Name="RightScrollRow2" Width="Auto"/>
</Grid.ColumnDefinitions>
<RepeatButton Content="left" x:Name="btnLeft" Grid.Column="0" Style="{DynamicResource RepeatButtonStyleLeft}" Click="btnLeft_Click"></RepeatButton>
<ScrollViewer Grid.Column="1" VerticalScrollBarVisibility="Hidden" HorizontalScrollBarVisibility="Hidden" x:Name="sv" CanContentScroll="True" Margin="0" Height="73" >
<ListBox x:Name="list1" ItemsSource="{Binding Reg, ElementName=Window}" Background="{x:Null}" BorderBrush="{x:Null}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"></StackPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button x:Name="TestButton" HorizontalAlignment="Center" Height="71" Width="151"
Margin="5,0,10,0" Style="{DynamicResource ButtonStyleTest}"
Click="TestButton_Click"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ListBox>
</ScrollViewer>
<RepeatButton Content="right" x:Name="btnRight" Grid.Column="2" Style="{DynamicResource RepeatButtonStyleRight}" Click="btnRight_Click"></RepeatButton>
</Grid>
When i navigate the items that are being loaded in the stackpanel (buttons) only continues scrolling appears, and content slowly appears.
A possible solution to this would be using HorizontalOffSet but this involving giving a exactly distance which i think would not be a good solution at all.
Thanks in advance,
Jackz
I would go about this differently.
I would add the scroll bar in the style. Read this and see the note in the Scrollbar section.
http://www.wpfsharp.com/2012/03/18/itemscontrol-vs-listbox-vs-listview-in-wpf/
I got a Scrollviewer with an ItemsControl inside. The ItemsControl, depending on the number of items in it, can be scrolled or not with the SCrollViewer.
I have a Control that display some total values of all the items. This control needs to be just under the ItemsControl. If there is not many items, it will be just under the last, not on the bottom of the page, with a lot of space between.
I can't achieve to do that.
Has anyone any ideas ? Here some of my code :
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<DockPanel Grid.Row="0">
<!-- This is my Total Control - just a Border for the example -->
<Grid Margin="0,4" MaxHeight="60" VerticalAlignment="Top" DockPanel.Dock="Bottom">
<Border Background="Red" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
</Grid>
<ScrollViewer HorizontalContentAlignment="Stretch" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"
>
<ItemsControl HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ItemsSource="{Binding Path=ListeQuestions}" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<concUCQuest:UCQuestion HorizontalAlignment="Stretch" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</DockPanel>
Here is a link to a picture of what i try to get
I tried DockPanel, Grid into Grid, but I've got out of ideas.
Thanks for your help !
Adding a VerticalAlignment="Stretch" to the Scrollviewer should do the trick.
<Grid>
<DockPanel LastChildFill="True">
<!-- This is my Total Control - just a Border for the example -->
<Grid DockPanel.Dock="Bottom">
<Border Background="Red" Height="10"/>
</Grid>
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<ItemsControl HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ItemsControl.ItemTemplate>
<DataTemplate>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</DockPanel>
</Grid>
This works for me.
You can also use a ListBox with a DataTemplate, instead of wrapping an ItemsControl with a ScrollViewer.
The main issue people seem to have with the vertical scrollbar not appearing is because they use a stackpanel. I went through my complete visual tree and my listbox is not in a stackpanel anywhere.
Here is the XAML that I use:
<Grid>
<Grid.Resources>
<local:ReportToListItem x:Key="reportToListItem" />
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="3" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ListBox Background="PaleGoldenrod" x:Name="Controller_Domain_Reports_OpenReports">
<ListBox.ItemTemplate>
<DataTemplate>
<ContentControl cal:View.Model="{Binding Converter={StaticResource reportToListItem}}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Border Grid.Row="1" Background="Black" Height="3" HorizontalAlignment="Stretch" />
<ListBox Background="Magenta" Grid.Row="2" x:Name="Controller_Domain_Reports_ClosedReports">
<ListBox.ItemTemplate>
<DataTemplate>
<ContentControl cal:View.Model="{Binding Converter={StaticResource reportToListItem}}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
Neither listbox gets a scrollbar if it extends beyond the height of the window for me. What am I overlooking?
Just putting this up to close this off properly:
Do'h.. The shellview had a nice copy pasted list of rowdefinitions all set to auto. Changed the one that contains this view to * and now it works as expected.