Problem using * in Grid sizes - wpf

When I set a column's width or a row's height to star, and I fill in content that is bigger than the available rectangle, the row keeps on growing 'underground':
<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="100" Width="100">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<StackPanel>
<Button Content="Button" />
<Button Content="Button" />
<Button Content="Button" />
</StackPanel>
<StackPanel Grid.Row="1"
ScrollViewer.CanContentScroll="True"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.IsDeferredScrollingEnabled="True">
<Button Content="Button" />
<Button Content="Button" />
<Button Content="Button" />
</StackPanel>
</Grid>
</Window>
I want that StackPanel should not grow underground, instead it should show scrollbars.
Note, I need all the size dynamic so everything changes according to the user resizing the parents.
I have the same issue with columns.
PS. RowDefinition.Height is always * by default.
UPDATE
I guess the problem is the grid and the previous snippet I posted didn't provide the whole story, please review:
<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="200">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition/>
<RowDefinition Height="20"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="1">
<StackPanel>
<TextBlock Text="Hello"/>
<TextBox Text="World!"/>
</StackPanel>
<ScrollViewer>
<StackPanel>
<Button Content="Button"/>
<Button Content="Button"/>
<Button Content="Button"/>
<Button Content="Button"/>
<Button Content="Button"/>
</StackPanel>
</ScrollViewer>
</StackPanel>
</Grid>
</Window>

I'm not sure that StackPanel has a built in ScrollViewer so setting the ScrollViewer.* attached proeprties really has no effect on it.
Have you tried wrapping the StackPanel with a ScrollViewer explicitly? For example:
<ScrollViewer Grid.Row="1"
ScrollViewer.CanContentScroll="True"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.IsDeferredScrollingEnabled="True">
<StackPanel>
<Button Content="Button" />
<Button Content="Button" />
<Button Content="Button" />
</StackPanel>
</ScrollViewer>

Related

Textbox does not show a verticalscrollbar

<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="WpfApplication1.MainWindow"
Title="MainWindow" Height="350" Width="550" MinHeight="350">
<DockPanel Background="BlanchedAlmond">
<DataGrid Background="YellowGreen" DockPanel.Dock="Top" MinHeight="100">
</DataGrid>
<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal" FlowDirection="RightToLeft" Margin="10" Background="YellowGreen">
<Button HorizontalAlignment="Right" Click="Button1Add_Click" Margin="5,0">Add text 1</Button>
<Button HorizontalAlignment="Right" Click="Button2Add_Click">Add text 2</Button>
<Button HorizontalAlignment="Right" Click="Button1_Click" Margin="5,0">Toggle textbox 1</Button>
<Button HorizontalAlignment="Right" Click="Button2_Click">Toggle textbox 2</Button>
</StackPanel>
<Grid Background="Red">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBox x:Name="TextBox1" Grid.Row="0" Background="AliceBlue" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">Test 1</TextBox>
<TextBox x:Name="TextBox2" Grid.Row="1" Background="AliceBlue" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">Test 2</TextBox>
</Grid>
</DockPanel>
</Window>
In the example above I am trying to achieve that the two textboxes in the middle just fill the available space between the top datagrid and the bottom stackpanel with buttons.
They have to divide that space between them depending on their text-content and their visibility.
Both properties can change by databindings, I simulated that with the click events.
But when the space is filled up they have to show a vertical scrollbar when needed.
The code sample above is not good. When I add text to a textbox, the grid-row becomes larger but disappears from the visible region, no scroll bar.
EDIT: I ended up with:
<ScrollViewer Background="AliceBlue" VerticalScrollBarVisibility="Auto">
<StackPanel Orientation="Vertical">
<Label x:Name="Label1" Margin="0,6,0,0">Test 1:</Label>
<TextBox x:Name="TextBox1" Padding="0,6"></TextBox>
<Label x:Name="Label2" Margin="0,6,0,0">Test 2:</Label>
<TextBox x:Name="TextBox2" Padding="0,6" ></TextBox>
</StackPanel>
</ScrollViewer>
You need to add a ScrollViewer in your XAML around the content.
ScrollViewer on MSDN
<ScrollViewer>
Content
</ScrollViewer>

Docking Top/Bottom/Left/Right/Filling in WPF

i am win form developer. whenever i want to set any control at top/Bottom/Left/Right position in its container then we just play the controls dock property in winform. so just guide me how can i place a control in its container top/Bottom/Left/Right position in such a way as a result when contain size change then control position will not change in wpf.
after searching google i came to know how filling works with Dock property and it is like
<Window ...Other window props... >
<Canvas HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<!-- Canvas items here... -->
</Canvas>
</Window>
So guide me how to set any control at top/Bottom/Left/Right position in its container with code snippet.
UPDATE
i just come to know dock panel can be use for my requirement like this way
<DockPanel LastChildFill="True">
<Button Content="Dock=Top" DockPanel.Dock="Top"/>
<Button Content="Dock=Bottom" DockPanel.Dock="Bottom"/>
<Button Content="Dock=Left"/>
<Button Content="Dock=Right" DockPanel.Dock="Right"/>
<Button Content="LastChildFill=True"/>
</DockPanel>
any other way can i achieve this without using DockPanel. thanks
You can use a Grid, (note the star sizing)
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<!-- If not specified, then Grid.Column="0" Grid.Row="0" are defaults-->
<Button Content="Dock=Top" Grid.ColumnSpan="3"/>
<Button Content="Dock=Bottom" Grid.Row="2" Grid.ColumnSpan="3"/>
<Button Content="Dock=Left" Grid.Row="1"/>
<Button Content="Dock=Right" Grid.Column="2" Grid.Row="1" />
<Button Content="LastChildFill=True" Grid.Column="1" Grid.Row="1"/>
</Grid>
You can use margins and alignments (margins are approximate here)
<Grid>
<Button Content="Dock=Top" VerticalAlignment="Top"/>
<Button Content="Dock=Bottom" VerticalAlignment="Bottom"/>
<Button Content="Dock=Left" HorizontalAlignment="Left" Margin="0,35"/>
<Button Content="Dock=Right" HorizontalAlignment="Right" Margin="0,35" />
<Button Content="LastChildFill=True" Margin="75,35"/>
</Grid>
You can use StackPanels (this one needs more work to make it fill the space)
<StackPanel Orientation="Vertical" VerticalAlignment="Center" HorizontalAlignment="Center">
<Button Content="Dock=Top" />
<StackPanel Orientation="Horizontal" >
<Button Content="Dock=Left" />
<Button Content="LastChildFill=True" />
<Button Content="Dock=Right" />
</StackPanel>
<Button Content="Dock=Bottom" />
</StackPanel>
<DockPanel>
<Button DockPanel.Dock="Left" Content="Left"></Button>
<Button DockPanel.Dock="Right" Content="Right"></Button>
<Button DockPanel.Dock="Top" Content="Top"></Button>
<Button DockPanel.Dock="Bottom" Content="Bottom"></Button>
<Button DockPanel.Dock="Left" Content="Center" HorizontalAlignment="Center"></Button>
</DockPanel>

How to have filled video at top and show label at bottom. (Fill and Anchor)

In Winforms, I use Fill and Dock to achieve this.
I have a "Page" where I would like to play a video file and also show the label at the bottom. I would like the page to be able to stretch and for the video to stretch and to have the label stay at the bottom of the page.
My attempts so far always results in the video covering the label when it is played. How can this be fixed?
(Other controls in the StackPanel have been omitted)
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.MediaElementExample" >
<DockPanel LastChildFill="True">
<MediaElement Source="media\numbers.wmv" Name="myMediaElement"
LoadedBehavior="Manual" UnloadedBehavior="Stop"
MediaOpened="Element_MediaOpened" MediaEnded="Element_MediaEnded"
DockPanel.Dock="Top" Margin="50" />
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal"
Height="30" DockPanel.Dock="Bottom" Margin="50">
<TextBlock Margin="5" VerticalAlignment="Center">
Video Label
</TextBlock>
</StackPanel>
</DockPanel>
</Page>
Solution (with thanks to Daniel May):
<Grid Height="Auto">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<MediaElement Source="media\numbers.wmv" Name="myMediaElement" LoadedBehavior="Manual" UnloadedBehavior="Stop"
MediaOpened="Element_MediaOpened" MediaEnded="Element_MediaEnded" />
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal" Height="30" Grid.Row="1">
<Button Content="Button" Height="23" Name="button1" Width="75" Click="button1_Click" />
</StackPanel>
</Grid>
You can achieve this using a Grid.
<Grid Height="300" Width="300">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<MediaElement Source="media\numbers.wmv"
Name="myMediaElement"
LoadedBehavior="Manual"
UnloadedBehavior="Stop"
MediaOpened="Element_MediaOpened"
MediaEnded="Element_MediaEnded" />
<TextBlock Margin="5"
Grid.Row="1"
VerticalAlignment="Center"
Text="Video Label" />
</Grid>
Using the Height attribute on the second RowDefinition, you force that row to size to it's contents. The preceding RowDefinition then fills the rest of the available space (in your case, your MediaElement).

My WPF UserControl must never get wider than the containing ButtonBar

I have bound at top the Width of the UserControl to the Width of the ButtonGrid at top.
It does not work. I want my UserControl always that wide as the width of the ButtonGrid. The problem is loading documents with a long name > Sum(Width of 3 buttons) makes the UserControl as wide as the document name. Now imagine having document names with 100 chars or longer and you add documents the UserContol will bump and jump...
<UserControl x:Class="TBM.View.DocumentListView"
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:Behaviours="clr-namespace:FunctionalFun.UI.Behaviours"
xmlns:Helper="clr-namespace:TBM.Helper"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="300"
Width="{Binding ElementName=ButtonGrid,Path=Width}"
>
<UserControl.Resources>
<Helper:BooleanToVisibilityConverter x:Key="boolToVisibilityConverter" />
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ListBox
SelectionMode="Extended"
VirtualizingStackPanel.IsVirtualizing="True"
VirtualizingStackPanel.VirtualizationMode="Recycling"
Behaviours:MultiSelectorBehaviours.SynchronizedSelectedItems="{Binding SelectedDocumentViewModelList,Mode=TwoWay}"
Width="Auto"
Focusable="True"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollBarVisibility="Auto"
Grid.Row="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Name="documentListBox"
BorderThickness="1"
ItemsSource="{Binding DocumentList}"
Visibility="{Binding ElementName=documentListBox,Path=HasItems, Converter={StaticResource boolToVisibilityConverter}}"
>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<!--<TextBlock Text="{Binding Path=Id}" />-->
<TextBlock Text="{Binding Path=DocumentName}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<UniformGrid x:Name="ButtonGrid"
Grid.Row="1"
Rows="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Bottom"
>
<Button Command="{Binding Path=DeleteDocumentCommand}" HorizontalAlignment="Stretch" Content="Delete" />
<Button Command="{Binding Path=AddDocumentCommand}" HorizontalAlignment="Stretch" Content="Add" />
<Button Command="{Binding Path=OpenDocumentCommand}" HorizontalAlignment="Stretch" Content="Open" />
</UniformGrid>
</Grid>
</UserControl>
You could also set the width of the ParentGrid(containing the control) to a fixed size, en then horizontal alignment to Stretch
Try 2 stuff
Use horizontal alignment on user control to stretch
Set binding to MaxWidth same as Width binding

How to set WPF ScrollViewer height dynamically?

I have the following test sample:
<Window x:Class="WpfScrollTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="200" Width="200">
<Border>
<StackPanel>
<Label Width="Auto" Height="Auto" Content="Text to mess up the scrollview"/>
<ScrollViewer Height="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type Border}}, Path=ActualHeight}">
<StackPanel>
<Button MinWidth="100" MinHeight="100" Content="Button"/>
<Button MinWidth="100" MinHeight="100" Content="Button"/>
</StackPanel>
</ScrollViewer>
</StackPanel>
</Border>
</Window>
Which creates this:
My question is how do I set the ScrollViewer.Height dynamically while still being able to see the bottom of the scrollbar? In my sample, the Height of the ScrollViewer is too long because of the Label above it ..
I don't want to fix the Height of the ScrollViewerto a static value.
I would recommend to remove the outer StackPanel to a Grid, since Stackpanel wont respect the children size. And remove the ScrollViewer.Height binding. Now you just need to create two RowDefinition for the Grid and place the Label to Grid.Row=0 and ScrollViwer to Grid.Row=1.
Code is below. So my tip here is, use StackPanel/Canvas only if necessary and may be for the inner levels. Try to use Grid more to get very dynamic layouts.
<Border>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Width="Auto" Height="Auto" Content="Text to mess up the scrollview"/>
<ScrollViewer Grid.Row="1" >
<StackPanel>
<Button MinWidth="100" MinHeight="100" Content="Button"/>
<Button MinWidth="100" MinHeight="100" Content="Button"/>
</StackPanel>
</ScrollViewer>
</Grid>
</Border>

Resources