WPF Listbox wont scroll Vertical - wpf

Within a Groupbox I have a Listbox, ListboxItems are defined in the XAML as well. The Listbox is defined:
<ListBox Name="lvAvoidCountry" Margin="5,5,5,5"
Background="Transparent"
ScrollViewer.VerticalScrollBarVisibility="Visible"
ScrollViewer.HorizontalScrollBarVisibility="Disabled" >
Items are defined like this:
<ListViewItem >
<CheckBox Name="chkAlbanien" Tag="55">
<StackPanel Orientation="Horizontal">
<Image Source="images/flag_albania.png" Height="30"></Image>
<TextBlock Text="Albanien" Margin="5,0,0,0"></TextBlock>
</StackPanel>
</CheckBox>
</ListViewItem>
If I remove the Scrollviewer Settings I get horizontal scrolling and the Items are well formatted - correct width. If I use the scrollviewer settings the items get cut off so that all items are placed on the listbox. (eg. the flag is shown, the checkbox is shown but the text is just "Alba").
Thanks for any hints!

As the name implies, ScrollViewer.HorizontalScrollBarVisibility="Disabled" disables horizontal scrolling. If you do that, but your ListBoxItems are too long, they'll get cut off. The StackPanel won't grow or shrink to fit into the ListBox, and it won't "wrap" your items to fit into the ListBox if it's too narrow, even if you add TextWrapping to the TextBlock. It's very stubborn. I think your main problem is that StackPanel.
Instead of a StackPanel, try using a Grid with 2 columns defined like so:
<ListViewItem >
<CheckBox Name="chkAlbanien" Tag="55">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Source="images/flag_albania.png" Height="30"/>
<TextBlock Grid.Column="1"
TextWrapping="Wrap"
Text="Albanien" Margin="5,0,0,0"/>
</Grid>
</CheckBox>
</ListViewItem>
Auto will "shrinkwrap" the image columns, and * will give the text all remaining space. Then add TextWrapping to your textblock in case it's still too long.
Edited: added more complete code example and changed my answer slightly.

if you want vertical scrolling in a listbox then don't put it in a stackpanel,instead use a grid.

Related

Vertical gridlines in a ListView

I've got a WPF ListView that I'm using as a GridView. Is there any way I can get vertical gridlines in there?
The ListView has a MinHeight specified, so I'd like the GridLine to go all the way to the bottom of the grid, so it'll fill the empty space.
This seems to be a rather tricky problem. Is is possible to solve?
This is how I do it.
<ListView Grid.IsSharedSizeScope="True"
ItemsSource="{Binding Path=MyList,FallbackValue='12345'}" >
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*" SharedSizeGroup="col0"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="1*" SharedSizeGroup="col2"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Margin="10,0"
Text="{Binding Path=Name, FallbackValue='Name goes here'}"/>
<Border Grid.Column="1" Margin="0,-2"
BorderBrush="DarkGray"
BorderThickness="0,0,1,0" />
<TextBlock Grid.Column="2" Margin="10,0"
Text="{Binding Path=DateModified, FallbackValue='Date goes here'}"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The SharedSizeGroup and Grid.IsSharedSizeScope properties are key to this way of doing it. The Margin="0,-2" property on the Border makes sure the dividing line looks like a continuous vertical line. If you add vertical margin to the two textblocks, you will need to increase the negative vertical margin of the border.
This will take care of lining things up into two uniformly sized columns with a vertical line between them, but it won't extend into areas where there is no data. A ListView might not be the best option if you want that functionality.
Adding some data to the MyList property in the ViewModel gives this as a result:
Of course, the MyList property needs to be a list or collection of a class that has Name and DateModified as properties.

Limit width of TextBox to the width of the ListView that contains it

I am working on a MVVM app (the examples here are not very MVVM though, its just a mockup).
I have a ListView, that binds to a collection of TextItemViewModel instances, the view for these are defined in TextItemView. Each TextItemView contains a Grid with one Auto column and on * column to fill. The fill column contains a TextBox where the user can enter text.
I want the TextItemViews to fill the horizontal space of the ListView (this works), like so:
However, when a user enters long text in a box, I want it to expand in Height but not in Width. At the moment, the Width increases and the ListView gets a scrollbar, like so:
My ListView code looks like this: (I've taken out the MVVM Binding code and set the ItemsSource in the code-behind for this example)
<ListView Name="listview"
SelectionMode="Single"
Margin="5"
MinHeight="50"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch" />
And my TextItemView code looks like this:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Button Content="SomeButton"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Margin="5"
Grid.Column="0" />
<TextBox Text="{Binding Path=NoteText}"
TextWrapping="Wrap"
AcceptsReturn="True"
AcceptsTab="True"
VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Disabled"
HorizontalAlignment="Stretch"
Margin="5"
Grid.Column="1" />
</Grid>
Can anyone advise me on how to force the TextItemView to fill the width of the ListView (as it does), but to then wrap the TextBox and expand TextItemView in Height when the TextBox fills up?
OK I got this now thanks to WPF - How to stop TextBox from autosizing?
Trick is to add the following to ListView definition:
ScrollViewer.HorizontalScrollBarVisibility="Disabled"

Listbox height binding not working properly & Image control proportional resizing

During developement of some program I've encountered some problems. The first is that I've bound the 'Height' property of listbox control to 'ActualHeight' of my stackPanel. Here's some XAML code I have:
<ListBox Name="listQuotes" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
Width="{Binding ElementName=stackPanelQuotes, Path=ActualWidth}"
Height="{Binding ElementName=stackPanelQuotes, Path=ActualHeight}"
ItemsSource="{Binding}" ItemTemplate="{StaticResource quotesFeedTemplate}"
Background="Transparent" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
</ListBox>
When I'm expanding my window, size of listbox changes, but when I make it smaller again, the listbox itself doesn't change back, in fact even scrollbar remains the same range...
So how am I supposed to get this work properly?
Second thing is that my program consists of two parts - header and the main part
Header must remain static, while the the main part (two listboxes in two colums) must resize with the window. By resizing I mean that width should affect both, the header and main part, and height should only affect the main part
Normal view
Corrupted view
And the third thing. How can I make my image resize propotionally (lets say 3:4) whe I'm resing the window (no matter wich - width or height)
You couldget the effect you want by removing the height and width bindings and leaving them as automatic.
<Grid Name="Quotes">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="4*" />
</Grid.ColumnDefinitions>
<ListBox Grid.Column="0" MinWidth="250" Name="listQuotes" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
ItemsSource="{Binding QuotesList}"
Background="Transparent" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
</ListBox>
<ListBox Grid.Column ="1" MinWidth="250" Name="listQuotes2" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
ItemsSource="{Binding QuotesList}"
Background="Transparent" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
</ListBox>
</Grid>
You can get the proportional sizing you want by using a grid with the Columnn definitions I posted. Those will stay in proportion as you resize.

WPF ListView TextBlock TextWrapping

I am building a ListView that needs to have five columns - the first one needs to have text that can be any length and needs to wrap whenever the window size changes (in addition to changing the row height so the wrapped text is visible) and the other four columns are a static width of 45. I've been searching for hours on this and every solution I come across either requires a static width or doesn't work.
Solutions tried:
Column widths of auto, 1*, 2*, etc. (settings ignored)
DockPanel (settings ignored)
WrapPanel (ignored)
Setting Width to RelativeSource of parent for ActualWidth (ignored)
Any ideas? It seems like a significant number of people have had this same problem, but I would highly prefer to not have to go the static width route for this column. Especially since the content just gets cut off when I do that anyway (even with height="Auto" for the row). The width of the overall window could be as small as 1024, but could also be 1600+ which is why I want dynamic sizing. That way smaller screens will have the content wrap and larger screens will just show the one line since the content fits.
Here is the XAML:
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="45" />
<ColumnDefinition Width="45" />
<ColumnDefinition Width="45" />
<ColumnDefinition Width="45" />
</Grid.ColumnDefinitions>
<!-- This is the TextBlock that needs to wrap its content (and
change the height of the row (so the full content is still
visible) to whatever the available space is, but should not
make overall ListView wider than the parent's width. -->
<TextBlock Text="{Binding Content}" Padding="20,6,6,6" />
<!-- These four blocks will have other content eventually, but only need
to be 45 wide -->
<TextBlock Text="X" Grid.Column="1" HorizontalAlignment="Center" />
<TextBlock Text="X" Grid.Column="2" HorizontalAlignment="Center" />
<TextBlock Text="X" Grid.Column="3" HorizontalAlignment="Center" />
<TextBlock Text="X" Grid.Column="4" HorizontalAlignment="Center" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
Not so easy...but it can be done.
I wrote a solution for you. In short, use Expression Blend to create a copy of the ListView Template and delete the ScrollViewer surrounding the ItemPresenter.
Here is a more indepth explanation:
How to have the TextBlock in a left column of a Grid in a ListView Template expand or shrink with text wrapping?
<ListView HorizontalContentAlignment="Stretch" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListView.ItemTemplate>
...
</ListView.ItemTemplate>
</ListView>
I'd add TextWrapping="Wrap" to the first TextBlock element.

TextBox expanding with surrounding Grid but not with text

A window has a Grid with two columns. The left column contains a control with a constant width but with a height that adapts. The right column contains a TextBox that takes up all remaining space in the Grid (and thereby in the Window).
The Grid is given a minimal width and height and is wrapped within a ScrollViewer. If the user resizes the window to be smaller than the minimal width/height of the Grid, scrollbars are displayed.
This is exactly how I want it to be. However, a problem occurs when the user starts typing text. If the text is to long to fit in one line in the TextBox, I want the text to wrap. Therefore I set TextWrapping="Wrap" on the TextBox. But since the TextBox has an automatic width and is wrapped in a ScrollViewer (its actually the whole Grid that is wrapped), the TextBox just keeps expanding to the right.
I do want the TextBox to expand if the window is expanded, but I don't want the TextBox to expand by the text. Rather the text should wrap inside the available TextBox. If the text don't fit within the TextBox height, a scrollbar should be displayed within the TextBox.
Is there a way to accomplish this?
Below is some code that shows my problem:
<Window x:Class="AdaptingTextBoxes.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="300" Width="400" Background="DarkCyan">
<Grid Margin="10" Name="LayoutRoot">
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<Grid MinWidth="300" MinHeight="200">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Margin="0,0,10,0" Content="Button" Width="100" />
<TextBox Grid.Column="1" AcceptsReturn="True" TextWrapping="Wrap" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Auto" />
</Grid>
</ScrollViewer>
</Grid>
</Window>
You could use an invisible border (its hacky but it works - its how I tend to sort out dynamic textbox sizes in Xaml):
<Border BorderThickness="0" x:Name="border" Grid.Column="1" Margin="0.5" />
<TextBox Grid.Column="1" AcceptsReturn="True" TextWrapping="Wrap" Width="{Binding ActualWidth, ElementName=border}" Height="{Binding ActualHeight, ElementName=border}" />
Have you tried setting the MaxWidth property on just the TextBox?
Edit after OP's comment
I would try getting rid of the ScrollViewer. The sizing used in the Grid's layout should take care of re-sizing and the scroll bar settings on the TextBox should take care of the rest.
The answer is based on Leom's answer.
The solution works great when you enlarge the window, but the resizing is not smooth when you make the window smaller. As the textbox participates in the grid's layout, it has to perform layout process multiple times. You can fix that by putting the texbox in the canvas, so the change of the size of the textbox no longer triggers the grid's re-layout.
The updated code:
<Border BorderThickness="0" x:Name="border" Grid.Column="1" Margin="0.5" />
<Canvas Grid.Column="1">
<TextBox AcceptsReturn="True" TextWrapping="Wrap" Width="{Binding ActualWidth, ElementName=border}" Height="{Binding ActualHeight, ElementName=border}" />
</Canvas>

Resources