Reputation: 123
I have a ListBox, but I wasn't able to fix the header, so it wouldn't scroll with the rest of the page. After searching for the reason, I found that in the main window, where everything is placed via ContentControl, there is one ScrollViewer wrapped around everything:
<ScrollViewer Margin="0,0,0,0" >
<ContentControl x:Name="content" Margin="0,0,0,0"/>
</ScrollViewer>
I can't really delete it, because I am working just on one content page that is gonna be implemented into this project later. Is it possible to disable this ScrollViewer from within my window? Or somehow make it stop influencing my content?
EDIT: To make it clear. this code (above) is in MainWindow that I can't edit. Contents are added in .cs by content.Content = new (content class)
. In one of those classes, which I am working on, I have:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="20" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="1" Orientation="Horizontal">
<TextBlock Text ={x:Static ...}>
<Text Block ...>
</StackPanel>
<ScrollViewer Grid.Row="2">
<ListBox>...</ListBox>
</ScrollViewer>
</Grid>
And the problem is, that this scrollviewer doesnt work, because there is one wrapped arount it on higher level, where I can't get...
Upvotes: 1
Views: 1436
Reputation: 169400
Is it possible to disable this ScrollViewer from within my window? Or somehow make it stop influencing my content?
You could handle the Loaded event of your control, find the parent ScrollViewer in the visual tree and disable it using the ScrollViewer.SetVerticalScrollBarVisibility method.
Window.xaml:
<Window x:Class="WpfApplication1.Window14"
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"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
Title="Window14" Height="300" Width="300">
<Grid>
<ScrollViewer Margin="0,0,0,0" Height="200" >
<ContentControl x:Name="content" Margin="0,0,0,0">
<ContentControl.Content>
<local:UserControl1 />
</ContentControl.Content>
</ContentControl>
</ScrollViewer>
</Grid>
</Window>
UserControl1.xaml:
<UserControl x:Class="WpfApplication1.UserControl2"
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:WpfApplication1"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300" Background="Yellow" ScrollViewer.VerticalScrollBarVisibility="Hidden">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Rectangle Height="100" Fill="Green" />
<ListBox x:Name="lv" Grid.Row="1">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</UserControl>
UserControl1.xaml.cs:
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
this.Loaded += UserControl1_Loaded;
lv.ItemsSource = Enumerable.Range(0, 1000);
}
private void UserControl1_Loaded(object sender, RoutedEventArgs e)
{
ScrollViewer sv = FindParent<ScrollViewer>(this);
if (sv != null)
{
ScrollViewer.SetVerticalScrollBarVisibility(sv, ScrollBarVisibility.Disabled);
}
}
private static T FindParent<T>(DependencyObject dependencyObject) where T : DependencyObject
{
var parent = VisualTreeHelper.GetParent(dependencyObject);
if (parent == null) return null;
var parentT = parent as T;
return parentT ?? FindParent<T>(parent);
}
}
Upvotes: 1
Reputation: 1185
Since i cant find a way to do this, i'm proposing this AttachedProperty
. You can disable the ParentView ScrollViewer
by using this AttachedProperty
.This is one way for achieving your requirement.
public class ScrollViewerExtension : DependencyObject
{
public static bool GetDisableParentScrollViewer(DependencyObject obj)
{
return (bool)obj.GetValue(DisableParentScrollViewerProperty);
}
public static void SetDisableParentScrollViewer(DependencyObject obj, bool value)
{
obj.SetValue(DisableParentScrollViewerProperty, value);
}
// Using a DependencyProperty as the backing store for DisableParentScrollViewer. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DisableParentScrollViewerProperty =
DependencyProperty.RegisterAttached("DisableParentScrollViewer", typeof(bool), typeof(ScrollViewerExtension), new PropertyMetadata(false,OnDisableParentScrollViewerChanged));
private static void OnDisableParentScrollViewerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is FrameworkElement)
{
(d as FrameworkElement).Loaded += (_, __) =>
{
var scrollViewer = FindAncestor(d as Visual, typeof(ScrollViewer)) as ScrollViewer;
if (scrollViewer != null && (bool)e.NewValue)
scrollViewer.VerticalScrollBarVisibility = ScrollBarVisibility.Disabled;
};
}
}
public static Visual FindAncestor(Visual startingFrom, Type typeAncestor)
{
if (startingFrom != null)
{
DependencyObject parent = VisualTreeHelper.GetParent(startingFrom);
while (parent != null && !typeAncestor.IsInstanceOfType(parent))
{
parent = VisualTreeHelper.GetParent(parent);
}
return parent as Visual;
}
return null;
}
}
and in your view,
<Grid attached:ScrollViewerExtension.DisableParentScrollViewer="True">
<Grid.RowDefinitions>
<RowDefinition Height="20" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="1" Orientation="Horizontal">
<TextBlock Text ={x:Static ...}>
<Text Block ...>
</StackPanel>
<ScrollViewer Grid.Row="2">
<ListBox>...</ListBox>
</ScrollViewer>
Upvotes: 1
Reputation: 1894
Maybe you could size your content in a way that the surrounding ScrollViewer
has no reason to provide scrolling. Instead, provide scrolling in your ListBox by limiting its height:
<!-- When the StackPanel is not bigger than the ScrollViewer, there should be no reason for it to scroll your title out of sight. If there is Padding in your scroll viewer, an additional converter may bre required to modify the height accordingly -->
<StackPanel Height="{Binding ActualHeight, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ScrollViewer}}">
<TextBlock Text="TitleForMyListBox"/>
<ListBox Height="50">
<!-- ... -->
</ListBox>
</StackPanel>
I used 50 as Height. Of course, this should be replaced by your desired height. If you want it dynamic, you can use a Multibinding
to the ActualHeight
of the StackPanel
and TextBlock
and a converter returning (ActualHeight
of StackPanel
) - (ActualHeight
of TextBlock
).
EDIT: applying this to the code in your edit:
<Grid Height="{Binding ActualHeight, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ScrollViewer}}">
<Grid.RowDefinitions>
<RowDefinition Height="20" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal">
<TextBlock Text ={x:Static ...}>
<Text Block ...>
</StackPanel>
<ListBox Grid.Row="1">...</ListBox>
</Grid>
I have:
Grid.Row
numbersScrollViewer
as the ListBox
will provide scrolling when its height is limitedListBox
to 50. Again, this should be replaced by your desired height. If you want it dynamic, you can use a Multibinding
to the ActualHeight
of the Grid
and StackPanel
and a converter returning (ActualHeight
of Grid
) - (ActualHeight
of StackPanel
).Binding
for the Height
of the Grid
Upvotes: 1