Give a WPF Grid the width of a ScrollViewer minus the scrollbar - wpf

I have a WPF UserControl with two Grids above each other. The bottom Grid is in a ScrollViewer. The idea is to have the first Grid be the header of the second Grid. I'm having trouble with the width of the columns however. Both Grids should take up all the space they can (the width of the Window), but the top Grid should of course be a little less wide, because there's a scrollbar on the right of the bottom Grid.
This is the simplified Xaml I've got:
<UserControl>
<DockPanel>
<Grid DockPanel.Dock="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
</Grid>
<ScrollViewer>
<Grid>
<Grid.ColumnDefintions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefintions>
</Grid>
</ScrollViewer>
</DockPanel>
</UserControl>
This renders fine actually, except that the most right column of the top Grid extends over the scrollbar, which I want to avoid.!
Here is an image of the result: Grid column and width of scrollbar. The red indicates where the column/cell is now, but I want it to stop at the blue line. I've tried SharedSizeGroups, but that seems to make my Grids small again (not take up the full space of the window).

<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" Name="sv">
<Grid MinWidth="{Binding ElementName=sv, Path=ViewportWidth}" MinHeight="{Binding ElementName=sv, Path=ViewportHeight}" />
</ScrollViewer>
The problem is setting up a correct dependency between the ScrollViewer container size and the grid size. Let us consider just the width: the binding above allows the ScrollViewer to expose the horizontal scrollbar only if necessary:
enlarging a single column of the grid (eg. with a splitter) does not provoke the resizing of the other columns (which would happen if you bind Width instead MinWidth).
Using the ViewportWidth instead of ActualWidth takes into account the scrollbar width, if there is one.
Just try

Found the solution here. I gave my top Grid a Width:
Width="{Binding ElementName=BottomGrid, Path=ActualWidth}"

Related

How do I bind the height of a StackPanel to the height of the containing Grid in WPF?

Im relatively new to WPF so I'm sorry in advance if there is a simple solution to this. However, I am trying to bind the height of a StackPanel to its containing Grid. I understand that a StackPanel automatically resizes to fit its elements but I would like to bind it to the Grid so that it does not do this. Right now the stack panel does not resize with the window since it remains the
size it needs to be in order to fit its elements.
Here is what I have so far:
<Grid x:Name="MainGrid" Grid.Row="2" Margin="1" Drop="Grid_Drop"
AllowDrop="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="175"/>
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel x:Name="SidePanel" Grid.Column="0" Height="{Binding
ActualHeight, ElementName=MainGrid, Mode=OneWay}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition/>
</Grid.RowDefinitions>
<local:DeviceTreeView x:Name="deviceTree" PyngInfo="{Binding
PyngSystemVm.PyngInfo}" Grid.Row="0"/>
</StackPanel>
<-- There is more code here but it is not important for answering this
question -->
</Grid>
I tried binding the height of "SidePanel" to the actual height of "MainGrid" but when I run this code and inspect the elements the Grid resizes with the window but the StackPanel does not. The StackPanel and the Grid even have different heights which doesn't make sense to me as their heights should be bound together.
I have also tried wrapping the entire StackPanel in a border and binding to that but that also did not work.
You don't need to bind the height of the StackPanel, simply setting its VerticalAlignment to Stretch will do it. However... You are still not going to get what I think you want. The StackPanel only stacks its child controls, it does not adjust them (at least not in the "stack" direction). Look into using a different control like Grid or UniformGrid or just expand your existing grid to have rows as well as columns.

WPF: ColumnSpan in UniformGrid

I know that UniformGrid haven't attached properties ColumnSpan and RowSpan. But what i really need is container with fixed width and inner cells also with fixed widths, except few UIElements, that should be filled in few cells.
For example:
<UniformGrid Columns="4"> <TextBlock>1</TextBlock>
<TextBlock>2</TextBlock>
<TextBlock Grid.ColumnSpan="2">34</TextBlock>
UniformGrid is ideal for me except this situation: last TextBlock is not fill two cells.
Is it possible use some other solution to give the needed result?
Thank you for any advise!
P.S.And... why XAML parser is not stops with error where process this markup?
You could use a Grid with the columns having varying * widths:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<TextBlock>1</TextBlock>
<TextBlock Grid.Column="1">2</TextBlock>
<TextBlock Grid.Column="2">34</TextBlock>
</Grid>
I wanted use only XAML, but for now I still not found the answer. So, i've used following solution: placed all my elements in horizontal WrapPanel and set width for each element in code.

datagrid scrollbars not showing in frame

I have a DataGrid in a UseraControl. In a separate UserControl I have a frame pointing to the UserControl with the DataGrid. When the application runs, the datagrid is shown in the frame. but the Datagrid's scrollbars are not visible. Not in the conventional sence anyways.
If I place the frame in this mannor, it show the scroll bars.
d:DesignHeight="768" d:DesignWidth="1366">
<Grid DataContext="{Binding Source={x:Static app:detailsSQL.Instance}}">
<Frame ScrollViewer.VerticalScrollBarVisibility="Visible" ScrollViewer.HorizontalScrollBarVisibility="Visible" ScrollViewer.CanContentScroll="True" Source="/content/membership/members/details/tabs/grid.xaml"/>
</Grid>
However if i do this, the scroll bars dissapear, although it's still very capable of scrolling with the mouse wheel.
d:DesignHeight="768" d:DesignWidth="1366">
<Grid DataContext="{Binding Source={x:Static app:detailsSQL.Instance}}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Frame Grid.Column="1" Source="/content/membership/members/details/tabs/grid.xaml"/>
</Grid>
Even if I don't put the Frame in a GridColumn, it still won't show the scroll bars. Is there a reason why it's this sensitive?
Scrollbar will only show if the available area to draw the control is more than the allocated area. Here you can put a scrollbar around the grid in your usercontrol.
or if you are intending to make your usercontrol itself scrollable then you might consider to put it around the frame.
eg:
<ScrollViewer Height="",Width="">
<Frame Grid.Column="1" Source="/content/membership/members/details/tabs/grid.xaml"/>
</ScrollViewer>
and try giving your ScrollViewer a size .

How to prevent TextBox from stretching vertically inside Grid

In the markup below, the text box vertically to fills the entire grid row, no matter how big the row's height is. For a single line text box this does not look good. I need it to center vertically instead and have the height just enough to fit the current font. Setting the Height property on the text box helps but I do not want to hard code the height in case the font changes.
<Grid FocusManager.FocusedElement="{Binding ElementName=TitleBox}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox Name="TitleBox"
Text="{Binding Title, UpdateSourceTrigger=PropertyChanged}"
Grid.Column="0" />
<Button Command="{Binding CreateCommand}"
IsDefault="True"
Grid.Column="1">Create</Button>
</Grid>
Set the VerticalAlignment of the text box to Center. The default is Stretch which explains why it stretches to fill the entire grid cell:
VerticalAlignment="Center"

Letting a child control width size to fit and limiting its max value

Edit: I try rephrasing my question, sorry if it was not clear. Thanks to all anyway.
Say I have a UserControl whose layout has a grid with 1 row x 3 columns, the first 2 autosized and the third star-sized:
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ComboBox MinWidth="80" MaxWidth="150" .../>
<CheckBox Grid.Column="1" VerticalAlignment="Top".../>
<TextBox Grid.Column="2" MaxHeight="400" TextWrapping="Wrap" HorizontalAlignment="Stretch"...>
</Grid>
The TextBox has text wrapping and its vertical scrollbar visibility set to auto and its horizontal one hidden.
Now, I have some window including a ListBox whose items are instances of this UserControl, like:
<ListBox HorizontalContentAlignment="Stretch".../>
The ListBox is in a 1-column star-sized grid and thus stretches to fit all the available width in its container. When I resize the container of this ListBox the ListBox too resizes as expected as it is stretched in a star-sized Grid column; and the same holds true for the ListBox items', which too are stretched and in this case happen to be instances of a UserControl with the above layout (3 columns in a grid, the 3rd star-sized).
The problem is that the TextBox in the 3rd column of the UserControl used as a listbox item should not automatically increase its width when I type into it some long text: it should just wrap, increasing its height (up to a maximum height; then the vertical scrollbar will appear). In other words, its MaxWidth should be determined by the available space, like its Width.
How should I code my XAML for this?
That should be the behavior by default, based on the code you've posted.
Try setting your TextBox's HorizontalAlignment="Stretch"

Resources