简体   繁体   中英

Can i disable scrollviewer from within?

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...

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:

  • fixed the Grid.Row numbers
  • removed your ScrollViewer as the ListBox will provide scrolling when its height is limited
  • limited the height of the ListBox 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 ).
  • Added a Binding for the Height of the Grid

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>

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);
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM