I have a WPF form with some text fields and two ListBoxes:
<TextBlock>Label</TextBlock>
<TextBox Text="{Binding Input}"/>
<TextBlock>List Label</TextBlock>
<ListBox ItemsSource="{Binding Items1}"/>
<TextBlock>Second List Label</TextBlock>
<ListBox ItemsSource="{Binding Items2}"/>
I'd like for the two ListBoxes to expand vertically to fit their container, but for each one to stop expanding once its scrollbar is no longer necessary. The closest I've come is with a grid:
<Grid VerticalAlignment="Top">
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="*" MinHeight="40" />
<RowDefinition Height="auto" />
<RowDefinition Height="*" MinHeight="40" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0">
<TextBlock>Label</TextBlock>
<TextBox Text="{Binding Input}"/>
<TextBlock>List Label</TextBlock>
</StackPanel>
<ListBox Grid.Row="1" ItemsSource="{Binding Items1}"/>
<TextBlock Grid.Row="2">Second List Label</TextBlock>
<ListBox Grid.Row="3" ItemsSource="{Binding Items2}"/>
</Grid>
However, then the space taken up by the list boxes is always the same due to the asterisk row height, so if one list stops growing, the remainder of the height to match the other list is left as empty space at the bottom of the grid.
What you want is a DockPanel...
<DockPanel >
<TextBlock DockPanel.Dock="Top">Label</TextBlock>
<TextBox Text="{Binding Input}" DockPanel.Dock="Top"/>
<TextBlock DockPanel.Dock="Top">List Label</TextBlock>
<ListBox Grid.Row="1" ItemsSource="{Binding Items1}" DockPanel.Dock="Top" MinHeight="40" MaxHeight="200"/>
<TextBlock Grid.Row="2" DockPanel.Dock="Top">Second List Label</TextBlock>
<ListBox Grid.Row="1" ItemsSource="{Binding Items2}" MinHeight="40"/>
</DockPanel>
This fulfills all of your requirement. The container is completely filled. The listboxes stop expanding when scrollbars are no longer needed. However if there are too many items in the 1st listbox the 2nd one will disappear completely. This is why I put in a max height for the first list box.
Related
I have created a UserControl that is suppose to display some text and then present a listbox for the user to select some item.
It is supposed to strech to the height to the grid cell it is placed in. And if there are more items than can fit on screen then to display a vertical scrollbar. After much trial and error I have finally managed to get it working as expected. But only when the row height is a pixel value. If I use any partial (by partial I mean the star symbol), the grid cell's height is not contained. Since I need the app the match screen size I need the partials to work.
Putting 100 items in the listbox suddenly makes the height of the entire grid is around 11000 (which I think is everything with no contraint). Meaning there is no scrollbar. See [Screenshot] https://i.stack.imgur.com/faES9.png.
I have a similar issue with my TextBox only horizontally. It will only activate when clicking on a specific pixel since it is empty the width is only 1 pixel. I hope someone can help me point out where I am going wrong, cause since I'm having more than one issue I suspect the problem is on my end.
This is my XAML code.
<UserControl x:Class="PackingStation.UserControls.SearchItemListing"
x:Name="SearchItemListingRoot"
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"
xmlns:local="clr-namespace:PackingStation.UserControls"
mc:Ignorable="d"
d:DesignHeight="1000" d:DesignWidth="1000">
<Grid DataContext="{Binding ElementName=SearchItemListingRoot}"
x:Name="TheGrid"
VerticalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height=".1*" />
<RowDefinition Height=".1*" />
<!-- If this value isnt a pixel value it will not vertically strech to available space -->
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel HorizontalAlignment="Center"
Margin="0,0,0,0"
x:Name="TheHeadLineField"
Grid.Row="0"
Grid.Column="1">
<Label Style="{StaticResource LabelStyleHeadline32}"
Content="{Binding Title}"
HorizontalAlignment="Left"/>
<Label Style="{StaticResource LabelStyleText}"
HorizontalAlignment="Left"
Content="{Binding SubTitle}"
FontSize="20"/>
</StackPanel>
<!-- Search Field -->
<Border Style="{StaticResource Border6}"
x:Name="TheSearchField"
Grid.Row="1"
Grid.Column="1"
Background="{StaticResource ColorSummaryPanelBackground}"
BorderBrush="{StaticResource ColorSummaryPanelBorder}"
BorderThickness="1"
Margin="0,40,0,0">
<StackPanel Orientation="Horizontal"
Height="78"
HorizontalAlignment="Stretch">
<Image Stretch="Uniform"
Height="24"
Source="pack://application:,,,/WpfUI;component/Icons/Search.png"
Margin="36,0,0,0"
VerticalAlignment="Center"/>
<!-- Search Textbox -->
<!-- Similar issue with this textbox, only horizontally. With no content you have to hit a specific pixel to activate it -->
<TextBox Style="{StaticResource TextBoxSearchInlay}"
Name="TbxSearchTerm"
TextChanged="TextBoxBase_OnTextChanged"
HorizontalContentAlignment="Stretch"
HorizontalAlignment="Stretch"
Margin="20,0,0,0"/>
</StackPanel>
</Border>
<!-- Search results listings -->
<ListBox ItemsSource="{Binding Items}"
x:Name="TheListBox"
Grid.Row="2"
Grid.Column="1"
SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
ScrollViewer.VerticalScrollBarVisibility="Auto"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel HorizontalAlignment="Stretch" Margin="0,-10,0,-10">
<Label Style="{StaticResource LabelSearchItem}"
Content="{Binding Name}"
HorizontalContentAlignment="Stretch"
HorizontalAlignment="Stretch"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</UserControl>
I could repro your problem when I put your UserControl in a StackPanel. When it's in a Grid the ListBox shows its vertical scrollbar. So, try your UserControl in a Grid.
I think this answer will give a good explanation about Grid and StackPanel stretching behavior.
I have held of asking here in hopes to find an answer by searching first but I have been unsuccessful.
I have what is a search filter bar on the left side of my window, looks something like this (I have omitted most of the controls for size sake and because most of them are ComboBox and experiencing the same issue):
<Grid Grid.Column="0" Background="#FF1E2125">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<ScrollViewer x:Name="scroll_filter" Grid.Row="0" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
<StackPanel Grid.Row="0" Orientation="Vertical" Margin="0,0,0,10">
<TextBlock Grid.Row="0" Text="User" Foreground="White" VerticalAlignment="Center" FontSize="12" Margin="10,3,10,3"/>
<ComboBox x:Name="cbo_search_user" Grid.Row="1" Margin="10,3,10,3" SelectedIndex="0" IsTextSearchEnabled="True" TextSearch.TextPath="ID">
<ComboBox.ItemTemplate>
<DataTemplate>
<Grid Height="20">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding ID}" VerticalAlignment="Center" HorizontalAlignment="Left"/>
<TextBlock Grid.Column="1" Text="{Binding Full_Name}" VerticalAlignment="Center"/>
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<!-- Other controls omitted for clarity -->
</StackPanel>
</ScrollViewer>
<Button x:Name="btn_search" Grid.Row="1" Content="Search" Margin="10,3,10,10" VerticalAlignment="Bottom" Height="28" Foreground="White" Style="{StaticResource ButtonWithoutHover}" Background="#FF41B1E1" Click="btn_search_Click"/>
</Grid>
My ComboBoxes are being populated via ItemsSource from code behind and can contain multiple results so that the ComboBox gets its own ScrollViewer.
The ScrollViewer is there so that the controls are visible to the user if the window is resized.
The ScrollViewer scrolls fine with the mouse wheel (dragging the bars too) which is great, the problem however is that when I dropdown on a ComboBox with many items in I cannot scroll with the mouse wheel.
The ScrollViewer (if small enough and scrollable) seems to take over and scrolls the whole lot up and down instead of the items in the expanded ComboBox.
If the scrollbar isn't visible on the ScrollViewer, scrolling with the mouse wheel doesn't do anything and the only way to scroll in the ComboBox is by dragging it's scrollbar.
How can I make the ComboBox within the ScrollViewer scrollable with the mouse wheel so that users aren't forced to drag the scroll bars.
Thanks
This answer suggests using the FrameworkTemplate.FindName method like this
ScrollViewer sv = comboBox.Template.FindName("DropDownScrollViewer", comboBox) as ScrollViewer;
if (sv != null)
{
// Do something...
}
Below is my xaml code :
<Window x:Class="ScoresBank.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow">
<DockPanel LastChildFill="True">
<WrapPanel DockPanel.Dock="Top">
<ToolBar Height="25"></ToolBar>
</WrapPanel>
<WrapPanel DockPanel.Dock="Bottom">
<StatusBar Name="stbBottom" Height="25"
BorderThickness="2"
BorderBrush="Black">Example</StatusBar>
</WrapPanel>
<StackPanel DockPanel.Dock="Left">
<DockPanel LastChildFill="True">
<WrapPanel DockPanel.Dock="Top">
<Button Name="btnBrowseTags">TAGS</Button>
<Button Name="btnBrowseTitles">TITLES</Button>
</WrapPanel>
<ComboBox DockPanel.Dock="Top" Name="cbxCategory">
Example
</ComboBox>
<WrapPanel DockPanel.Dock="Bottom">
<TextBox Name="txtKeyword"></TextBox>
<Button Name="btnFind">Find</Button>
</WrapPanel>
<ListBox Name="lbxBrowse">
</ListBox>
</DockPanel>
</StackPanel>
<StackPanel DockPanel.Dock="Right">
<Button>Example</Button>
</StackPanel>
<Canvas>
</Canvas>
</DockPanel>
And this is my current layout view :
So, what I mean with filling the container are :
Making lbxBrowse to fill the mid-space of the DockPanel inside the left StackPanel.
Making txtKeyword to fill the WrapPanel.
Making stbBottom to fill the WrapPanel.
What I've tried :
It seems i've put them in a DockPanel with LastChildFill="True". But it seems doesn't work.
I don't know about this, since it's not possible to put it into a DockPanel first.
I don't know anything about this.
I don't use fixed size, since I need them to keep neat even when resized in multiple screen resolution. The fixed size on ToolBar and StatusBar seems required, otherwise, the text will be unseen.
P.S. If possible, I prefer the solution to be XAML code, rather than the C# code. Otherwise, C# code is fine too.
Thank you.
You should use a Grid. It is more easier to configure. Here is an example (I don't know exactly how you want to setup your layout).
<Window x:Class="SampleWpf.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="400" Width="600">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Margin="5" Content="TAGS"
Grid.Column="0" Grid.Row="0" />
<Button Margin="5" Content="TITLES"
Grid.Column="1" Grid.Row="0" />
<Button Margin="5" Content="EXAMPLES"
Grid.Column="2" Grid.Row="0"
HorizontalAlignment="Right"/>
<ComboBox Margin="5"
Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="1" />
<ListBox Margin="5"
Grid.Column="2" Grid.Row="1" Grid.RowSpan="2" />
<Button Margin="5" Content="EXAMPLE"
Grid.Column="2" Grid.Row="3" HorizontalAlignment="Left" />
</Grid>
</Window>
And the result:
With a grid you can set the height and the width of the columns and rows to a specific value (in points, pixels, cm, etc.), to column content (Auto) or proportional to the grid (with *).
Instead of using a StackPanel and DockPanel you can use Grid and set Grid.ColumnDefinitions and Grid.RowDefinitions. You can specify directly each row Height and each column Width. It's easier to use and it automaticly fit to content and container.
Link to the Image of my App
I want to detect if the 2 Pictures on canvas are neary each other, an than make some compare operation with the data that is embedded in the pictures if both are touched an near each other.
The brown Area is a ScatterView where i can drop picture elements an add them to the green listbox.
I can drop picture items directly from the blue list box to the brown drop area.
But when i drop them first on the yellow scatterview, then i can't get out of there to drop them on the brown scatterview.
<Grid ShowGridLines="True">
<Grid.RowDefinitions >
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<s:ScatterView
Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="2"
Grid.RowSpan="1"
x:Name="ScatterLayer"
Background="Yellow"
ItemContainerStyle="{StaticResource ScatterItemStyle}"
AllowDrop="True"
ItemTemplate="{StaticResource ImageAndCaptionTemplate}"
ItemsSource="{Binding ScatterItems}"
s:SurfaceDragDrop.Drop="ScatterLayer_Drop"
s:SurfaceDragDrop.DragEnter="ScatterLayer_DragEnter"
s:SurfaceDragDrop.DragCompleted="ScatterLayer_DragCompleted" >
</s:ScatterView>
<s:SurfaceListBox
Grid.Row="0" Grid.Column="2"
AllowDrop="True"
x:Name="ListBoxVerticalBasket"
VerticalAlignment="Top"
Background="GreenYellow"
ItemsSource="{Binding Path=BasketItems}"
ItemTemplate="{StaticResource BasketTemplate}" >
<s:SurfaceListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</s:SurfaceListBox.ItemsPanel>
</s:SurfaceListBox>
<s:SurfaceListBox
Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="2"
x:Name="ShoppingList"
AllowDrop="True"
s:SurfaceDragDrop.DragCompleted="OnShoppingListDragCompleted"
s:SurfaceDragDrop.DragCanceled="OnShoppingListDragCanceled"
PreviewMouseLeftButtonDown="OnShoppingListPreviewMouseLeftButtonDown"
PreviewMouseMove="OnShoppingListPreviewMouseMove"
PreviewMouseLeftButtonUp="OnShoppingListPreviewMouseLeftButtonUp"
ItemsSource="{Binding Path=LibraryItems}"
ItemTemplate="{StaticResource ImageAndCaptionTemplate}"
PreviewTouchDown="OnShoppingListPreviewTouchDown"
PreviewTouchMove="OnShoppingListPreviewTouchMove"
PreviewTouchUp="OnShoppingListPreviewTouchUp"
Background="#FF00BDD8">
<s:SurfaceListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" AllowDrop="True"/>
</ItemsPanelTemplate>
</s:SurfaceListBox.ItemsPanel>
</s:SurfaceListBox>
<s:ScatterView
Grid.Column="2"
Grid.Row="1"
Background="DarkGoldenrod"
Width="300"
Height="100"
x:Name="ScatterViewDropArea"
VerticalAlignment="Top"
HorizontalAlignment="Left"
AllowDrop="True"
s:SurfaceDragDrop.Drop="ScatterViewDropArea_Drop">
</s:ScatterView>
I think you should consider using the DragDropScatterView that comes with the Shopping Cart demo in the Surface SDK instead of ScatterView.
I am trying to get my data to display properly within a GridLayout, which is to be used as a DataTemplate for an Item within ListBox. Here is the code associated with what I am doing:
<Grid Name="FeedItemTemplate">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Image Source="{Binding ProfileImage}" Grid.RowSpan="2" Height="75" Width="75" VerticalAlignment="Center" Margin="1" />
<TextBlock Text="{Binding UserName}" Grid.Column="1" Foreground="#FFC8AB14" FontSize="28" HorizontalAlignment="Left"/>
<TextBlock Text="{Binding TimeStamp}" Grid.Column="2" TextWrapping="Wrap" FontSize="18" HorizontalAlignment="Center"/>
<TextBlock Text="{Binding Message}" Grid.Column="1" Grid.Row="1" Grid.ColumnSpan="2" TextWrapping="Wrap" FontSize="24" />
</Grid>
The issue is that using this layout, when TextWrapping is set to Wrap, the Item is displayed correctly, but when scrolling through the ListBox everything is really jittery, you cannot scroll in small increments, and it just jumps all over the place.
Any reason why it does this? As I said, only when TextWrapping is set to Wrap it does this. When its not used, it scrolls fine, but the text is all along one line and off the screen.
Does it keep jumping if you explicitly set the top-level Grid element's width to a fixed size?
For some reason that I do not fully understand, settings the ListBox's ItemsPanel property to a StackPanel might solve your problem:
<UserControl.Resources>
<ItemsPanelTemplate x:Key="MyItemsPanelTemplate">
<StackPanel/>
</ItemsPanelTemplate>
</UserControl.Resources>
...
<ListBox ... ItemsPanel="{StaticResource MyItemsPanelTemplate}"/>
This is a known issue with listbox scrolling in the current ctp when you have variable height items. The workaround for now is to set a fixed height on your listbox item content. You'll probably also notice the scroll bar doesnt properly go to the bottom all the time. The workaround fixes that too.
Reference.