I am using wpf and I got a pretty big table, which needs to be scrollable both horizontaly, as well as vertically. It also has headers at the top and the left. These need be fixed, because the table is way to big scroll to the header all the time.
I tried using an approach with grids and scrollviews like these Fixed header and footer outside scrollview, . This lead to my current structure:
<Scrollviewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Visible">
<Grid>
<!-- Here is the left Header
</Grid>
<Scrollviewer HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Disabled">
<Grid>
<!-- Rest of the table -->
</Grid>
</Scrollviewer>
</Scrollviewer>
However this seems to be intended only for applications which scroll only in one dircetion. But in my case I have 2 problems with this approach.
- The horizontal scrollview is not fixed to the bottom of the page. If you want to see the bar you have to scroll all the way to the bottom first.
- Currently only the header at the left is fixed, and i got no idea how to fix the one on the top. If I were to exclude this part of the grid again and put it outside everything else, then the top header would be outside the horizontal scollviewer. There is no way getting both headers into both scrollviewers AND fix them to the place.
Does anyone have an idea how to solve this. Idealy I could define the position of scrollviewer seperate from its content. In that case I could make one Grid, with both headers, the body of the table and the scrollviews, and then I could set the content the scrollviews so it scroll to the body of the table.
EDIT: Fot one Grid in the code. Here is the corrected Version.
<Scrollviewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Visible">
<Grid>
<Grid>
<!-- Here is the left Header -->
</Grid>
<Scrollviewer HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Disabled">
<Grid>
<!-- Rest of the table -->
</Grid>
</Scrollviewer>
</Grid>
</Scrollviewer>
Also to make it clear here is what I want
with green being the horizintal scrollbar and blue the vertical. Both should always be visible. Currently I only see the green one if I sroll all the way down.
The headers (Rwo x, Column x) need to be always visible. On the same time they also have to be included in the scrollbar. So on the left are always 10 rows visible, but if I scrolldown I see 12-22 for example.
I am using wpf and I got a pretty big table, which needs to be scrollable both horizontaly, as well as vertically. It also has headers at the top and the left. These need be fixed, because the table is way to big scroll to the header all the time.
I tried using an approach with grids and scrollviews like these Fixed header and footer outside scrollview, https://learn.microsoft/en-us/answers/questions/537119/how-to-freeze-grid-column-in-scrollviewer-or-achie. This lead to my current structure:
<Scrollviewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Visible">
<Grid>
<!-- Here is the left Header
</Grid>
<Scrollviewer HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Disabled">
<Grid>
<!-- Rest of the table -->
</Grid>
</Scrollviewer>
</Scrollviewer>
However this seems to be intended only for applications which scroll only in one dircetion. But in my case I have 2 problems with this approach.
- The horizontal scrollview is not fixed to the bottom of the page. If you want to see the bar you have to scroll all the way to the bottom first.
- Currently only the header at the left is fixed, and i got no idea how to fix the one on the top. If I were to exclude this part of the grid again and put it outside everything else, then the top header would be outside the horizontal scollviewer. There is no way getting both headers into both scrollviewers AND fix them to the place.
Does anyone have an idea how to solve this. Idealy I could define the position of scrollviewer seperate from its content. In that case I could make one Grid, with both headers, the body of the table and the scrollviews, and then I could set the content the scrollviews so it scroll to the body of the table.
EDIT: Fot one Grid in the code. Here is the corrected Version.
<Scrollviewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Visible">
<Grid>
<Grid>
<!-- Here is the left Header -->
</Grid>
<Scrollviewer HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Disabled">
<Grid>
<!-- Rest of the table -->
</Grid>
</Scrollviewer>
</Grid>
</Scrollviewer>
Also to make it clear here is what I want
with green being the horizintal scrollbar and blue the vertical. Both should always be visible. Currently I only see the green one if I sroll all the way down.
The headers (Rwo x, Column x) need to be always visible. On the same time they also have to be included in the scrollbar. So on the left are always 10 rows visible, but if I scrolldown I see 12-22 for example.
Share Improve this question edited Mar 14 at 8:33 Tobias asked Mar 13 at 16:17 TobiasTobias 3832 silver badges13 bronze badges 4 |1 Answer
Reset to default 1To get you started, I've played a bit with my idea and it worked, but I made it only for horizontal ScrollBar
.
You need 3 ScrollViewer
(for left/top headers and content) and 2 ScrollBar
. I simulate headers and content with some stripped background (to see how it scrolls).
The important part how to use single ScrollBar
to scroll content in many ScrollViewer
s. I went with "attached behavior" solution.
Xaml:
<Grid>
<Grid.Resources>
<GradientStopCollection x:Key="strippedGradient" x:Shared="False">
<GradientStop Offset="0" Color="Black" />
<GradientStop Offset="0.5" />
</GradientStopCollection>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<!-- left columns -->
<ScrollViewer Grid.Row="1" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden">
<TextBlock Width="50" Height="1000">
<TextBlock.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,20" MappingMode="Absolute" SpreadMethod="Repeat" GradientStops="{StaticResource strippedGradient}" />
</TextBlock.Background>
</TextBlock>
</ScrollViewer>
<!-- top columns -->
<ScrollViewer Grid.Column="1" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="hidden" local:ScrollViewerBehavior.HorizontalScrollBar="{Binding ElementName=horizontalScrollBar}">
<TextBlock Width="1000" Height="50">
<TextBlock.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="20,0" MappingMode="Absolute" SpreadMethod="Repeat" GradientStops="{StaticResource strippedGradient}" />
</TextBlock.Background>
</TextBlock>
</ScrollViewer>
<!-- content in the center -->
<ScrollViewer Grid.Row="1" Grid.Column="1" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden" local:ScrollViewerBehavior.HorizontalScrollBar="{Binding ElementName=horizontalScrollBar}">
<TextBlock Width="1000" Height="1000">
<TextBlock.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="20,20" MappingMode="Absolute" SpreadMethod="Repeat" GradientStops="{StaticResource strippedGradient}" />
</TextBlock.Background>
</TextBlock>
</ScrollViewer>
<!-- horizontal scrollbar at bottom -->
<ScrollBar x:Name="horizontalScrollBar" Grid.Row="2" Grid.Column="1" SmallChange="10" LargeChange="100" Orientation="Horizontal" />
</Grid>
Demo:
Behavior:
public class ScrollViewerBehavior : DependencyObject
{
public static ScrollBar GetHorizontalScrollBar(DependencyObject obj) =>
(ScrollBar)obj.GetValue(HorizontalScrollBarProperty);
public static void SetHorizontalScrollBar(DependencyObject obj, ScrollBar value) =>
obj.SetValue(HorizontalScrollBarProperty, value);
public static readonly DependencyProperty HorizontalScrollBarProperty = DependencyProperty.RegisterAttached(
"HorizontalScrollBar", typeof(ScrollBar), typeof(ScrollViewerBehavior), new PropertyMetadata((sender, args) =>
{
if (sender is not ScrollViewer scrollViewer)
throw new InvalidOperationException("Can only be applied to ScrollViewer");
// prevent in designer
if (Application.Current is not App)
return;
if (args.NewValue is ScrollBar scrollBar)
{
// Value={Binding HorizontalOffset}
scrollBar.SetBinding(ScrollBar.ValueProperty, new Binding()
{
Path = new(ScrollViewer.HorizontalOffsetProperty),
Source = scrollViewer,
Mode = BindingMode.OneWay,
});
// Maximum={Binding ScrollableWidth}
scrollBar.SetBinding(ScrollBar.MaximumProperty, new Binding()
{
Path = new(ScrollViewer.ScrollableWidthProperty),
Source = scrollViewer,
Mode = BindingMode.OneWay,
});
// ViewportSize={Binding VieportWidth}
scrollBar.SetBinding(ScrollBar.ViewportSizeProperty, new Binding()
{
Path = new(ScrollViewer.ViewportWidthProperty),
Source = scrollViewer,
Mode = BindingMode.OneWay,
});
scrollBar.Scroll += (s, e) => scrollViewer.ScrollToHorizontalOffset(scrollBar.Value);
}
}));
}
TODO: add vertical scrollbar similarly, fix bugs.
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744690827a4588199.html
ScrollViewer
can only have 1 children, shown xaml is invalid. Without some screenshots it's kind of hard to imagine what you want. "If you want to see the bar you have to scroll all the way to the bottom first" - this is solved by using "floating" scrollbars, i.e. don't use horizontal scrollbar ofScrollViewer
, but host additional one on the level of parent scrollviewer, so it will be always accessible, without need to scroll. – Sinatr Commented Mar 13 at 16:48