I want a container that have 3 columns and in each column, the cell can wrap it's content like the picture below
So far, I've done this:
<ListBox Name="listQuestion">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="3"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
But the result is every cell have the same size as the biggest cell.
If you want to have a grid with three separate lists as their columns you should be able to use a combination of a Grid and a listbox
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ListBox Grid.Column="0"/>
<ListBox Grid.Column="1"/>
<ListBox Grid.Column="2"/>
</Grid>
A grid will give you the most flexibility in your layout and allows you to have elements span multiple columns or rows. If you don't need all that flexibility you could use a stackpanel instead
<StackPanel Orientation="Horizonal">
<ListBox/>
<ListBox/>
<ListBox/>
</StackPanel>
Related
I have a 3 Level Nested ListView binded to the same 3 Level Nested Collection. MainItems are added at the 3rd level.
Unmodified, there are scrollbars on ALL the levels. On item added, I edit the Containing Grid of the ListViewItem to adjust the height dynamically.
I have succeeded on removing the 3rd Level Scroll Bar. However, I want to remove the 2nd Level also, which I can't seem to do.
When I try to adjust the height of the 1st Level ListViewItem, the scrollbars on the 1st Level just disappears but the height is not adjusted at all.
What I want to do is ONLY have the ScrollBar on the 1st Level and scroll from there.
Basically, something like this:
This is my current code:
<Grid x:Name="ParentGrid">
<ListView x:Name="Level1ListView"
ItemsSource="{Binding Path=Level1}">
<ListView.ItemTemplate>
<DataTemplate>
<Grid x:Name="GridLevel1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ToolKit_Controls:LayoutTransformControl Grid.Column="0">
<ToolKit_Controls:LayoutTransformControl.Transform>
<RotateTransform x:Name="rotateTransform" Angle="270"/>
</ToolKit_Controls:LayoutTransformControl.Transform>
<TextBlock Text="{Binding Path=Level1NameString}" FontSize="32" HorizontalAlignment="Center" />
</ToolKit_Controls:LayoutTransformControl>
<ListView x:Name="Level2ListView"
ItemsSource="{Binding Path=Level2}"
Grid.Column="1"
>
<ListView.ItemTemplate>
<DataTemplate>
<Grid x:Name="GridLevel2">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Border BorderBrush="White" BorderThickness="1" Grid.Row="0"/>
<TextBlock Text='{Binding Path=Level2Name}' Foreground="Black" FontSize="18"
Grid.Row="0"/>
<Grid x:Name="GridLevel3" Width="300" Height="100" Grid.Row="1">
<ListView x:Name="ListView_Level3" IsSwipeEnabled="False"
ManipulationMode="None"
ItemsSource="{Binding Path=Level3DisplayCollection}"
Grid.Column="1">
<ListView.ItemContainerTransitions>
<TransitionCollection>
<EntranceThemeTransition IsStaggeringEnabled="False" />
</TransitionCollection>
</ListView.ItemContainerTransitions>
</ListView>
</Grid>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapGrid Orientation="Horizontal" MaximumRowsOrColumns="1" ></WrapGrid>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
And the important code which changes the height on item added:
var GridLevel1 = TypedAssociatedObject.GetAncestors().Where(a => a.Named("GridLevel1")).FirstOrDefault() as Grid;
//GridLevel1.Height = GridLevel1.ActualHeight + 50;
var GridLevel2 = TypedAssociatedObject.GetAncestors().Where(a => a.Named("GridLevel2")).FirstOrDefault() as Grid;
GridLevel2.Height = GridLevel2.ActualHeight + 50;
var GridLevel3 = TypedAssociatedObject.GetAncestors().Where(a => a.Named("GridLevel3")).FirstOrDefault() as Grid;
GridLevel3.Height = GridLevel3.ActualHeight + 50;
Level 1 is commented out because when I add it, although the 2nd Scroll Bar is removed the ListViewItem height doesn't change, resulting in the UI being wrong and not showing everything. You also notice that the 1st level scrollbar remains the same size:
What I want is to extend the height of Header 1 so that everything still shows and the 1st Level Scrollbar on the right is the one that extends / grows.
Can anyone help point out what I am doing wrong?
Thank you!
Edit: This is a Windows store app.
Set the ItemsPanel to StackPanel in your inner list views. This way you would not need to adjust the height of each item.
Also to hide the scrollbars use ScrollViewer.VerticalScrollBarVisibility="Hidden" on your inner list views.
Have you considered using grouping?
I have a situation where I am trying to set the tab order (tabindex) for controls that are loaded dynamically. The main XAML looks like this:
<ItemsControl DockPanel.Dock="Top" ItemsSource="{Binding ItemsDataSource}" Name="overlayItems" ItemTemplate="{StaticResource DetailsTemplate}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
For example purposes, assume the DetailsTemplate is something simple like this:
<DataTemplate x:Key="DetailsTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="150" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="22" />
<RowDefinition Height="22" />
<RowDefinition Height="22" />
</Grid.RowDefinitions>
<Label Grid.Column="0" Grid.Row="0" Padding="0">Field 1</Label>
<TextBox Grid.Column="1" Grid.Row="0" Name="field1TextBox" TabIndex="0" Text="{Binding Field1Value}"/>
<Label Grid.Column="0" Grid.Row="1" Padding="0">Field 2</Label>
<TextBox Grid.Column="1" Grid.Row="1" Name="field2TextBox" TabIndex="1" Text="{Binding Field2Value}"/>
<Label Grid.Column="0" Grid.Row="2" Padding="0">Field 3</Label>
<TextBox Grid.Column="1" Grid.Row="2" Name="field3TextBox" TabIndex="2" Text="{Binding Field3Value}"/>
</Grid>
</DataTemplate>
This XAML works just fine except for the resulting tab order.
Assuming that the ItemsDataSource is a collection of a class and contains 3 instances of that class, three sets of the DetailsTemplate data template are created. However the tab order does not change, every field1TextBox remains at TabIndex 0. This means, instead of tabbing from the first instances of field1TextBox, to field2TextBox, to field3TextBox, the tab goes from the first instance of field1TextBox to the second instance of field1TextBox then to the third instance of field1TextBox then to the first instance of field2TextBox, and so on. My question is, how do I get the tab order corrected where, say, the second instance of the data template would have its text boxes tab indexes updated to 3, 4 and 5 respectively?
You'll find the answer in the KeyboardNavigation.TabNavigation Attached Property page from MSDN. This property Gets or sets the logical tab navigation behavior for the children of the element that this property is set on.
There are several possible values in the KeyboardNavigationMode Enumeration used that affect the tabbing order in different ways, but you're after the Local value, which has the effect that Tab Indexes are considered on local subtree only inside this container and ... [Navigation leaves the containing element when an edge is reached].
<Grid KeyboardNavigation.TabNavigation="Local">
...
</Grid>
I have a ListBox control that has been assigned to Grid.Column 0 which has a value of '*' defined for it's width, however when rendered there is a sizeable amount of space that is not being used.
I have also noticed that there is a border of sorts around the ListBox control itself, however I have not added one within the markup.
My UI (Areas of concern marked in Red):
My Markup:
<Window.Resources>
<DataTemplate x:Key="GameImagesTemplate" >
<StackPanel Orientation="Vertical">
<Image Source="{Binding FileInfo.FullName}" Margin="8,8,8,8" Height="70" Width="70" />
<Label Content="{Binding Name}" Width="70" />
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="GameTemplate">
<StackPanel>
<Label Content="{Binding Name}" Background="Gray" FontSize="16" />
<ListBox x:Name="imageContent" ItemsSource="{Binding FileList}" ItemTemplate="{StaticResource GameImagesTemplate}" ScrollViewer.HorizontalScrollBarVisibility="Disabled" >
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" IsItemsHost="True" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<ListBox x:Name="ContentList" ItemTemplate="{StaticResource GameTemplate}" Grid.Column="0" ScrollViewer.HorizontalScrollBarVisibility="Disabled" />
<StackPanel Grid.Column="1" Background="DarkGray">
<Button Click="OnLoad">_Load</Button>
<Button Click="OnSave">_Save</Button>
<Button Click="OnAdd">_Add</Button>
<Button Click="OnDelete">_Delete</Button>
</StackPanel>
</Grid>
How would I go about resolving both of the issues raised. Is it the default behaviour of the ListBox control?
Many thanks
Yes, that is the default behavior.
In the case of the alignment it looks like you have a WrapPanel in each ListBoxItem which doesn't have quite enough space to put another item on line 1. The remaining space is unused because of the HorizontalContentAlignment setting on ListBox defaulting to Left. This setting is in turn bound to by the default ListBoxItem. Setting HorizontalContentAlignment="Stretch" on your ListBox should fix that.
The outer border comes from the default setting for BorderBrush and BorderThickness. Setting BorderThickness="0" will get rid of it entirely.
There are some other default Padding settings that add some spacing in the default Styles and Templates. If you want to get more into those add a ListBox to a project in Blend and make a copy of its default Template and ItemContainerStyle and check out the XAML. Also consider using the base ItemsControl in cases where you don't need selection behavior, as it doesn't have any of these type of default settings.
How can I create horizontally oriented ItemsControl, where items are aligned the same way how these two labels are aligned in this Grid?
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Grid.Column="1">Text 1</Label>
<Label Grid.Column="3">Text 2</Label>
</Grid>
I already have a View for the items, so using ItemsTemplate is probably not an option.
Resources
Here are some tutorials and articles about creating your own custom panel. Hope this will help someone with similar problem...
UniformGrid for Silverlight
Animate WPF Datatemplate when item added to Listbox?
Creating Custom Panels In WPF
FishEyePanel/FanPanel - Examples of custom layout panels in WPF
WPF - A Constraining Stack Panel
About the closest you could get without writing your own panel would be:
<ItemsControl ItemsSource="{Binding TheItems}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="1"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Control.HorizontalAlignment" Value="Center"/>
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
Note that I'm .NET-less at the moment so cannot test the above.
I'd like to create a table on WP7. This is my current approach using a ListBox with a Grid as the data template.
<ListBox x:Name="ResultsList" Margin="12,0" Grid.Row="1">
<ListBox.Resources>
<DataTemplate x:Key="ResultsListItem">
<Grid d:DesignWidth="385" Height="28">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="88"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock x:Name="textBlock1" Margin="0,0,24,0"/>
<TextBlock x:Name="textBlock2" Margin="0,0,24,0"
VerticalAlignment="Top" Grid.Column="1"/>
<TextBlock x:Name="textBlock3" Margin="0,0,24,0"
VerticalAlignment="Top" Grid.Column="3"/>
</Grid>
</DataTemplate>
</ListBox.Resources>
<ListBox.ItemTemplate>
<StaticResource ResourceKey="ResultsListItem"/>
</ListBox.ItemTemplate>
</ListBox>
The problem is, that the resulting table's columns are not sized equally. The Grid's column definitions are applied to each row independently of the other rows. That means, if there is a long text in textBlock1, column 0 will be larger. In the next row there could be a shorter text in textBlock1, resulting in column 0 also being shorter than the column 0 in the previous row.
How can the columns in all rows be sized equally? I don't want to use fixed width because when the orientation changes from portrait to landscape the colums would resize automatically.
There is the HeaderedItemsControl, but as I understand it it is not available for Windows Phone 7?
This is a tricky problem! In WPF there exists the concept of a SharedSizeGroup, which allows you to share column widths across multiple grids, but this is not available in silverlight.
There are a few workarounds on the web:
http://www.scottlogic.co.uk/blog/colin/2010/11/using-a-grid-as-the-panel-for-an-itemscontrol/
http://databaseconsultinggroup.com/blog/2009/05/simulating_sharedsizegroup_in.html
Although neither are simple solutions.
You might also try Mike's AutoGrid:
http://whydoidoit.com/2010/10/06/automatic-grid-layout-for-silverlight/
Here is my solution using SharedSizeGroup as suggested by ColinE.
<ListBox x:Name="ResultsList">
<ListBox.Resources>
<SharedSize:SharedSizeGroup x:Key="Col1Width" />
<SharedSize:SharedSizeGroup x:Key="Col2Width" />
<SharedSize:SharedSizeGroup x:Key="Col3Width" />
<DataTemplate x:Key="ResultsListItem">
<StackPanel d:DesignWidth="385" Orientation="Horizontal">
<SharedSize:SharedSizePanel WidthGroup="{StaticResource Col1Width}">
<TextBlock x:Name="textBlock" MaxWidth="100" Text="{Binding A}"/>
</SharedSize:SharedSizePanel>
<SharedSize:SharedSizePanel WidthGroup="{StaticResource Col2Width}">
<TextBlock x:Name="textBlock1" MaxWidth="85" Text="{Binding B}"/>
</SharedSize:SharedSizePanel>
<SharedSize:SharedSizePanel WidthGroup="{StaticResource Col3Width}">
<TextBlock x:Name="textBlock2" MaxWidth="200" Text="{Binding C}"/>
</SharedSize:SharedSizePanel>
</StackPanel>
</DataTemplate>
</ListBox.Resources>
<ListBox.ItemTemplate>
<StaticResource ResourceKey="ResultsListItem"/>
</ListBox.ItemTemplate>
</ListBox>
Even the maximum with of each column can be controlled via the TextBlock's MaxWidth property. The SharedSizeGroups ensure that the TextBlocks have the same size in each row.
You can use WrapPanel. Set the following ItemsPanel in the Datatemple, you can just have textblock.
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<control:WrapPanel />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>