How to customize the visible area of the scroll viewer's content - wpf

The ScrollViewer's default behavior is, that the content stops on the bottom of the ScrollViewer's view port:
I would like to change the behavior, so that the content can be scrolled to the top of the scroll ScrollViewer's view port:
a) Is it possible to configure the existing scroll viewer that way?
b) If not, what is the best way to achieve that behavior?

Embed the scrollable content in a Grid with 3 rows. The scrollable content occupies the second row. The other two have the same Height of the ScrollViewer:
<ScrollViewer Height="50">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<YourScrollableContent Grid.Row="1"/>
</Grid>
</ScrollViewer>
I've no way to test it in order to see if this code is perfect, but I'm sure this can be a way :)
Maybe you can bind the Height of the 2 rows with the Height of the ScrollViewer:
<RowDefinition Height="{Binding Path=Height,
RelativeSource={RelativeSource AncestorType=ScrollViewer}}"/>

Related

Prevent focus/tabbing into non visible element in UI

For example, I have Grid with two rows and GridSplitter between them. When one the rows is not visible in UI (eg. splitter is all the way on top; real case scenario is more complicated with nested controls) elements are still reachable via tab key - I would like to prevent that.
I am aware of IsVisible property of FrameworkElement (is true even for such elements) and/or IsEnabled/IsTabStop and KeyboardNavigation class in general, but none of them solves my problem. My elements are usable etc., just not currently visible in UI because of grid splitter. Basically only framework elements which can be reached by mouse should also participate in tab key functionality.
Simplest case when it can be reproduced is following content of main window (move splitter to upper most position).
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="10"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBox Grid.Row="0" KeyboardNavigation.TabNavigation="Once"/>
<GridSplitter Height="10" Grid.Row="1" KeyboardNavigation.TabNavigation="Once" HorizontalAlignment="Stretch"/>
<Grid Grid.Row="2">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBox x:Name="PART_Problem" Grid.Row="0" KeyboardNavigation.TabNavigation="Once"/>
<TextBox Grid.Row="1" KeyboardNavigation.TabNavigation="Once"/>
</Grid>
</Grid>
Result should be that non-visible elements should be skipped and next visible element should be focused instead. This functionality should be compatible with KeyboardNavigation.ControlTabNavigation.
Edit 1: changed sample a little in order to show, that PART_Problem keeps ActualHeight to some non-zero value, which eliminates solutions based on size changes.
Try setting the property Focusable="False" in XAML

WPF button position dependent on another element

I would like to place my button always on the middle of the bottom frame of ScrollViewer. I am going to change both the size of window, and a size of ScrollViewer, but I want my button to be always as on the pictures.
Owing to the fact that i am following MVVM, I have just xaml. Basically, I would like to bind (live) the button top position from the pattern:
button.top = (scrollViewer.top + scrollViewer.height) - button.height/2
I would be grateful for your suggestions.
[EDIT] I forgot to add that all other controls are in grid rows and columns.
You can try to use Grid to achieve that. If you need to change the ScrollViewer size, just change ScrollGrid Grid size instead. To overlap bottom or top content, you can use negative margins for the button.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="100"/>
<RowDefinition Height="*"/>
<RowDefinition Height="100"/>
</Grid.RowDefinitions>
<Border Background="Red"/>
<Border Background="Red" Grid.Row="2"/>
<Grid x:Name="ScrollGrid" Grid.Row="1">
<ScrollViewer></ScrollViewer>
<Button Width="100" Height="100" VerticalAlignment="Bottom" HorizontalAlignment="Center"/>
</Grid>
</Grid>

How to add a buttom that is always visible after a scrollviewer?

I have a ScrollViewer which includes a lot of content (datagrids, stackpanels, textboxes, labels, etc...), and outside of it I want to add a button (PRINT), and it is important that the button is not part of the ScrollViewer. My goal is that the top 90% of my screen is the scrollviewer and the bottom 10% is a "frozen panel" that always shows the PRINT button, and this should remain true when maximized and minimized.
After having a lo of problems with 'the property content is set more then once' I realized I need to add both my ScrollViewer and the Button inside another container, so far the only one that seems to work is GRID - but honestly after you read this if you have anything else to recommend I am open to suggestions, I only used GRID because it seemed to almost give me what I wanted.
This is my code right now:
[Code]
<Window DataContext="{Binding PrintView, Source={StaticResource Locator}}" Width="900">
<Grid Height="Auto">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ScrollViewer Name="PrintView" Grid.Row="0" Height="Auto">
<StackPanel>
... a LOT of stuff ...
</StackPanel>
</ScrollViewer>
<Button Content="Print"
Margin="0,20,0,20"
Height="50"
Width="150"
FontSize="24"
FontWeight="Bold"
Grid.Row="1"
/>
</Grid>
</Window>
[Code]
When done like this my ScrollViewer doesn't have a Scrollbar so I see the first page but I cannot scroll down, also there is no PRINT button seen
One interesting test was to change the following:
<ScrollViewer Name="Apercu" Grid.Row="0" Height="600">
Now I see my scrollbar again (and I can scroll) and my PRINT button is beneth it and always visible (this is almost perfect) but when I maximumize my window the ScrollViewer stays 600 of height and as such well it doesn't acctually maximize (everything below the PRINT button is just white).
Any ideas? Is there another way I could specify my HEIGHTS or is there a different control I should be using (not GRID)?
Thanks,
Found it ...
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
And remove height from ScollViewer

DataGrid Sizing Issue

I am trying to load data into a datagrid but I am having a nightmare with sizes. My datagrid seem to take as much space as it wants. I want it to load into the current size and display scroll bars if needed.
Could someone explain how the sizing works thank you.
Example:
<Grid Name="MainUI" Height="Auto" Width="Auto">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<Grid Name="MainGrid" Grid.Row="1" VerticalAlignment="Top" Height="Auto" Width="Auto">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<TabControl TabStripPlacement="Bottom" Name="Main_Tab" VerticalAlignment="Top" Visibility="Visible" />
</Grid>
</Grid>
Within the tab control I create a datagrid on a new tab item in the code behind when this happens, the datagrid takes as much room as possible.
The datagrid of itemTab has no sizing on it when I load it.
Thanks
Setting the Height/Width to Auto means the control should take up as much space as it needs. This means if the control needs more space than is available in the UI, it's allowed to stretch the parent control and take up however much space it wants.
Remove the Height="Auto" and Width="Auto" to fix the issue
If it is still giving you trouble, try setting HorizontalAlignment and VerticalAlignment to Stretch. This will make the control will grow or shrink itself to take up all space available to it, however it won't expand the container it is in to take up additional space.

in wpf how do i make a datagrid fit the window height

I have a grid with 3 columns and 2 rows
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="10"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
I the lower left cell, i have a data grid, with AutoGenerateColumns=True which can load many rows. What I want to do is for the data grid height to maximize to fit the window, and for the user to be able to use the datagrid scrollbar to scroll the rows up and down.
What happens is that the datagrid flows of the bottom of the window, and even if i set the
ScrollViewer.VerticalScrollBarVisibility="Visible"
of the datagrid, the scrollbar has no effect and the rows flow downwards. Somehow the datagrid does not feel restricted...
What to do?
Try setting your DataGrid's HorizontalAlignment=Stretch and VerticalScrollBarVisibility=Auto
If that doesn't work, you may also need to bind the Grid's Height to the Window Height so that it doesn't auto-grow to fit its contents. Usually I use Height="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=ActualHeight}" (It might be RenderSize.ActualHeight instead of just ActualHeight... I forgot.
Another alternative is to use a DockPanel instead of a Grid since that control doesn't auto-grow to fit its contents. Instead it'll stretch its last child to fill the remaining space.
I had the same problem but binding to the Window height did not completely solve the problem for me. In my case the DataGrid still extended 2 to 3 inches below the Window's viewable area. I believe this was because my DataGrid started about 2 to 3 inches below the top of the Window.
In the end I found that it was not necessary to bind the DataGrid's height at all. All I had to do was change the DataGrid's direct container.
For me, the following XAML setup causes the DataGrid to extend beyond the size of the Window when enough rows are added. Notice that the DataGrid sits within a StackPanel.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="75"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0">
<!-- StackPanel Content accounting for about 2-3 inches of space -->
</StackPanel>
<!-- DataGrid within a StackPanel extends past the vertical space of the Window
and does not display vertical scroll bars. Even if I bind the height to Window
height the DataGrid content still extends 2-3 inches past the viewable Window area-->
<StackPanel Grid.Row="1">
<DataGrid ItemsSource="{StaticResource ImportedTransactionList}"
Margin="10,20,10,10" MinHeight="100">
</DataGrid>
</StackPanel>
</Grid>
However, simply removing the StackPanel fixed the problem for me.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="75"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0">
<!-- StackPanel Content accounting for about 2-3 inches of space -->
</StackPanel>
<!-- Removing the StackPanel fixes the issue-->
<DataGrid Grid.Row="1" ItemsSource="{StaticResource SomeStaticResource}"
Margin="10,20,10,10" MinHeight="100">
</DataGrid>
</Grid>
As the original post is quite old, I should note that I am using VS2017 and .Net Framework 4.6.1 but I am not sure if this has any bearing.
You have to define the column and row where the DataGrid is with *.
You say it is on the lower left cell. The row is ok but your column there has Width="Auto".
The AutoGenerateColumns=True gives a mess if Width="Auto".

Resources