Resizable WPF listbox inside Stack Panel? - c#

I'm trying to create a listBox inside a WPF control which (1) has a minimum height of 80 and (2) which the user can resize to larger vertical height, if desired to see more of the list items. I also want the control, when nested inside a vertical stackPanel, to expand in height as the user expands the list. I've been playing around with gridSplitter. My XAML is below:
<UserControl x:Class="MyControl.FieldControl_SelectFrom"
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:MyControl"
mc:Ignorable="d"
d:DesignWidth="342">
<Grid Background="{x:Static SystemColors.ControlBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" x:Name="textBlock_fieldName" HorizontalAlignment="Left" Margin="20,4,0,0" TextWrapping="Wrap" Text="FieldName" VerticalAlignment="Top" FontWeight="Bold"/>
<ListBox Grid.Row="1" x:Name="selectorBox" MinHeight="80" Height="auto" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Padding="0,0,0,0" Margin="20,4,38,4" VerticalContentAlignment="Center" />
<GridSplitter Grid.Row="2" Height="2" VerticalAlignment="Center"></GridSplitter>
<TextBlock Grid.Row="3" x:Name="textBlock_fieldInfo" HorizontalAlignment="Left" Margin="20,0,0,6" TextWrapping="Wrap" VerticalAlignment="Bottom" FontStyle="Italic" Foreground="Gray">Field Info</TextBlock>
</Grid>
</UserControl>
When I run the project, the listbox is expanded to show the entire contents - with no ability to resize.
What am I missing?

The default resize direction of the GridSplitter is GridResizeDirection.Auto. If you look at the documentation for GridResizeDirection.Auto about the rules that govern behavior of Auto, you'll notice that in your case the GridSplitter -- based on the defined rules as explained in the documentation -- is actually attempting to resize between columns, not rows as you want it to be.
You can make the GridSplitter work in row mode in basically two ways. One is to set the ResizeDirection of the GridSplitter explicitly to GridResizeDirection.Rows. This, however, would not fully solve the problem with the code given in your question.
Because, without specifying the width of the splitter or letting it stretch horizontally (neither of which you have done), the splitter remains a point-like or short vertical line-like element with a width of zero that's practically impossible to hit. So, basically you could tell the splitter to stretch horizontally, which will let the default Auto resize direction operate in Rows mode (and therefore does not require to set the ResizeDirection property explicitly) as well as give the splitter a size that can actually be hit/grabbed with the mouse pointer.

Related

UWP AutoCompleteBox in ContentDialog not sizing correctly - text area larger than drawn

I have an AutoCompleteTextBox in UWP is exhibiting a really odd behavior, and I can't figure out what's causing it. The TextBox is in a Grid, but the user can type past the bounds of the TextBox, so the first and last characters of each line are hidden behind the surrounding border. I've taken some screenshots to hopefully make this make more sense, as it's difficult to describe.
I've tried everything I can think of, but can't seem to get it to stop doing this. The only effect I had at all was in changing the HorizontalAlignment of the TextBox. Originally it was Stretch, and only the right side of the TextBox had cutoff letters. When I changed it to Center, it divided the cut-off section between both the left and right.
Does anybody have any ideas as to what's going on?
In the 1st picture, the actual TextBox area is defined by the box on the far outer edges of the ContentDialog [with the drag handles left of the (116)].
TextBox in VS Designer
In the second picture, the letters typed in the TextBox are 2 W's. If you look closely, you can just see the very right of the 1st W to the left of the full W there.
TextBox during execution
XAML:
<ContentDialog
x:Class="FlipPanelTest2.ComposeTweet"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:FlipPanelTest2"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
RequestedTheme="Dark"
Title="{Binding SendTo}"
Foreground="Gray"
Width="600"
PrimaryButtonText="Cancel"
SecondaryButtonText="Tweet!"
SecondaryButtonStyle="{StaticResource TweetContentDialogButtonStyle}"
PrimaryButtonStyle="{StaticResource CancelButtonStyle}"
PrimaryButtonClick="ContentDialog_PrimaryButtonClick"
SecondaryButtonClick="ContentDialog_SecondaryButtonClick">
<Grid Width="Auto">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBox x:Name="tweetText" Grid.Row="0" HorizontalAlignment="Center" VerticalAlignment="Stretch" Background="White" TextWrapping="Wrap" Margin="2" TextChanged="TextBox_TextChanged" MaxHeight="180" MinHeight="112" Width="540" />
<StackPanel x:Name="characterCount" Orientation="Horizontal" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Center">
<TextBlock x:Name="currentChars" HorizontalAlignment="Right" Grid.Row="1" FontSize="10" Text="{Binding TweetCharacters}" />
<TextBlock x:Name="charsDivider" HorizontalAlignment="Right" Grid.Row="1" FontSize="10" Text="/" />
<TextBlock x:Name="maxChars" HorizontalAlignment="Right" Grid.Row="1" FontSize="10" Text="{Binding MaxCharacters}" />
</StackPanel>
</Grid>
Well some more searching found the answer apparently. I hadn't thought to search for a max size on the ContentDialog, hence the reason I didn't find this before. Providing a link to the answer though for future people to use:
Quoted from ContentDialog max width:
In your App.xaml, try setting the ContentDialogMaxWidth to say, 800.
The default is 548. You might want to increase the height too.
<Application.Resources>
<x:Double x:Key="ContentDialogMaxWidth">800</x:Double>
<x:Double x:Key="ContentDialogMaxHeight">756</x:Double>
</Application.Resources>
ContentDialog max width
It's the last answer listed there, for some reason not the accepted answer. :)

Changing size of User Control

I'm having a problem with determining which element is responsible for a size misalignment. Here is a picture to illustrate it: click here to see it
The light grey area is the element size which I am trying to change, but cannot. The overall area is a User Control, the area inside the Tab is a WPF (as an element Host). I've tried changing both, but with no effect on the grey area (the other tabs are also affected by this). Here is the code for the hosted element (WPF):
<UserControl x:Class="SlideAnalyzer.DisplayAnalysis"
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:SlideAnalyzer"
mc:Ignorable="d"
d:DesignHeight="150.8" d:DesignWidth="201.2">
<Grid Name="displayGrid" Height="64" VerticalAlignment="Bottom" HorizontalAlignment="Center" Width="160" Margin="10,0,31.6,9.4" RenderTransformOrigin="0.496,0.94">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Expander x:Name="expander" Grid.Row="0" Header="Titel zu lang" HorizontalAlignment="Left" VerticalAlignment="Top" Width="180" Background="Red" Margin="-10,-56,0,0">
<Grid Background="AliceBlue">
<TextBlock TextWrapping="Wrap"
Margin="5"><Run Text="This is some text content."/></TextBlock>
</Grid>
</Expander>
</Grid>
The host itself is a normal User Control. I cannot seem to get the right size of the hosted element so that the preview really reflects reality (because when I run the Add-In, the size of the WPF differs)
I tried changing the Properties of the UserControl and I found that AutoSize has a big impact when True (by default False)
Thanks!

How to make a certain section scrollable

I have got the following XAML:
<StackPanel HorizontalAlignment="Center">
<Image Name="logo" Source="logo.png" Margin="0,0,0,50"/>
<ScrollViewer>
<Dashboard_Control:AlignableWrapPanel x:Name="wrapPanel"/>
</ScrollViewer>
<TextBlock FontWeight="Bold" HorizontalAlignment="Center" x:Name="txtBottomText"></TextBlock>
</StackPanel>
I would like that the wrapPanel is scrollable only, so that the txtBottomText control will always be at the bottom as you scroll, and the logo image control will always be at the top - essentially only allowing the wrapPanel to be scrollable.
I have tried adding a ScrollViewer as shown above, however it never shows. I even tried adding a property to always have the vertical scrollbar, however it appears without letting me scroll (the scrollbar is disabled).
I suspect that this is because my wrapPanel's content is dynamically generated at run-time like so:
wrapPanel.Children.Add(content);
Any ideas what I can do to fix this?
It's not because of your wrapPanel's content. but because you're using a StackPanel to contain everything.
StackPanels grow indefinitely in the direction determined by their Orientation property. By default, that's vertically.
In your case, that makes the ScrollViewer "think" it has enough available space to stretch itself to accomodate its content, instead of activating the scroll bars. So it simply gets bigger as the WrapPanel inside gets bigger, pushing the TextBlock down.
To avoid this, you need to use a different Panel that is able to properly assign the available space to each control. Like a Grid.
<Grid HorizontalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Image Name="logo" Source="logo.png" Margin="0,0,0,50"/>
<ScrollViewer Grid.Row="1">
<Dashboard_Control:AlignableWrapPanel x:Name="wrapPanel"/>
</ScrollViewer>
<TextBlock Grid.Row="2" FontWeight="Bold" HorizontalAlignment="Center" x:Name="txtBottomText"></TextBlock>
</Grid>
I usually say that StackPanels tend to be overused :P They're practical and easy to use, but they have a bunch of quirks and limitations that make them not suitable for many situations, like this one.
EDIT: Make sure, also, that the Grid is not contained inside another vertical StackPanel, a Grid row with Height set to Auto, or something like that.
If the Height of your WrapPanel exceeds the height of the control or window where you have put the controls, the Textblock below the Wrap Panel inside the Stack Panel is put after the Wrap panel and so it is below the scroll area.
To be able to leave the Textblock always visible you have two means:
1) limit the height of your Wrap panel
2) Use a container like a Grid with 3 rows instead of the stack panel and put the Row Heights of the Grid respectively to
Auto, *, Auto so that the image on top and the textblock on bottom use the space of their content and the Scroll panel uses all the space remaining
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Image Grid.Row ="0" Source="myimage.jpg" />
<ScrollViewer Grid.Row="1">
<WrapPanel Height="1200" Width="600">
<TextBlock>Ciao sono io</TextBlock>
</WrapPanel>
</ScrollViewer>
<TextBox Grid.Row="2" TextWrapping="Wrap" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Text="IO c'ero" />
</Grid>
You have to set a fixed heigh to your scrollviewer - if not, the scrollviewer takes as much space as he needs, in order to show the complete content of its children.
Solutions:
Set the Height property of your scollviewer
Use a grid instead of a stackpanel an set the first and third rowheight to auto

ListView Inside a Grid inside a ScrollViewer

I have a ListView inside a Grid which in turn is inside an "overall ScrollViewer".
Users should be able to scroll across the entire page horizontally and then scroll vertically down several child list like elements. While I am able to scroll horizontally, placing the outer ScrollViewer around the page content breaks my ListViews
Here is a cut down version of my XAML setup:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="140" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock x:Uid="Title" Text="Title"/>
<ScrollViewer Grid.Row="1" ZoomMode="Disabled"
VerticalScrollBarVisibility="Hidden"
HorizontalScrollBarVisibility="Auto"
VerticalScrollMode="Disabled"
HorizontalScrollMode="Enabled">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="380" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<!--My List-->
<ListView x:Name="MyList" Grid.Column="0" />
<Grid x:Name="AppointmentDetailView" Grid.Column="1">
<!--Some other stuff-->
</Grid>
</Grid>
</ScrollViewer>
</Grid>
If I set a fixed height on any parent of the ListView or the ListView itself the scrolling works as expected but fixing the height is undesirable for screens of varying sizes. I tried binding to the ActualHeight of the ListViews parents but no luck.
It seems like the ScrollViewers children are not constrained to the height available even when the ScrollViewer.VerticalScrollMode is disabled. Seems rather odd to me, I would have expected the ScrollViewer's layout logic to be similar to Grid in the direction it has been disabled.
Any help with this is appreciated, Thank you!
I found a workaround that involves wrapping my ScrollViewer in a Grid and binding to the outer Grids ActualHeightProperty on the child element of the ScrollViewer. its a bit of a hack but does what I need it to and goes something like this
<Grid x:Name="ScrollViewerContainer" ...>
<ScrollViewer VerticalScrollMode="Disabled" ...>
<!--Page Content-->
<Grid Height="{Binding ActualHeight, ElementName=ScrollViewerContainer}" ...>
....
Personally I feel like the ScrollViewer should not allow its children to determine its Width/Height when the scroll mode is disabled in a particular direction as it breaks nested ScrollViewer's. It should revert back to the available space. But hey, I'm not Microsoft..

WPF grid layout and cell content margins

I am working on a WPF control whose content is a grid. I am relatively new to WPF so I am wondering if the below is the right way to go about this.
I placed two labels in the grid, both in the same column but adjacent rows:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="UntitledProject8.Window1"
x:Name="Window"
Title="Window1"
Width="200" Height="200">
<Grid x:Name="LayoutRoot">
<Grid HorizontalAlignment="Left" VerticalAlignment="Top" Width="100" Height="100"/>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Content="1.23" FontSize="18" HorizontalAlignment="Center" VerticalAlignment="Bottom"/>
<Label Grid.Row="1" Content="45" FontSize="48" HorizontalAlignment="Center" VerticalAlignment="Top"/>
</Grid>
I set the labels' vertical alignment so that the label on row zero is aligned to the bottom and the label on row 1 is aligned to the top.
Now, this is close to what I want but I need the actual text of the label in row 1 to be closer to the text of label in row zero. To do this I set the margin of the label in row 1 to a negative value:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="UntitledProject8.Window1"
x:Name="Window"
Title="Window1"
Width="200" Height="200">
<Grid x:Name="LayoutRoot">
<Grid HorizontalAlignment="Left" VerticalAlignment="Top" Width="100" Height="100"/>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Content="1.23" FontSize="18" HorizontalAlignment="Center" VerticalAlignment="Bottom"/>
<Label Grid.Row="1" Content="45" FontSize="48" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,-20,0,0"/>
</Grid>
Is that the right way to do it? Granted that my examples above are simplistic but as the grid contents grow and get more complicated (such as including other layout containers) is setting different values for control margins the correct way to make adjacent cells closer or farther apart?
I am just a little concerned since I am trying my best to avoid hard coding any types of "designer" values like I did when working with WinForms (such as setting exact coords for location and values for sizes) and would like to let the layout manager just take care of it. However, it looks like setting the margin is the only way to go.
Thanks for the help :)
That looks good! The only thing I was caught a little off guard with was the -20 for the top margin (instead of 20 for the bottom which should do the same thing), but I would only change that for clarity.
The main thing to note is the container of choice, which Grid will definitely work for you. Another feature of this is that as you stretch the Grid, the distance between your elements will proportionally grow (probably what you want anyway). The only weakness of the Grid is that it's not the most efficient. Mainly because you can do so much with it.
You could accomplish the same thing as above with a canvas (with the stretching feature) or if you didn't want the distance to stretch you might try a stackpanel, which is also going to be more efficient than the Grid. There are a few other panels as well, but becoming acquainted with what they can do (and how well they perform) is really helpful, especially when having to create more complex layouts.
As for the Margin, yeah that, along with setting width and height, are standard ways of setting spacing.

Categories

Resources