Access ScrollViewer from within a style

Hello all.

I am trying to create two buttons to replace ScrollViewer's own scrollbar left and right buttons. I have the ScrollViewer named sv1 in place within a style applied to a ListBox, but my click events cannot see it. On building I get "The name "sv1" does not exist in the current context" in Page1.xaml.cs.

Any help would be greatly appreciated

Page1.xaml
......

<Style TargetType="{x:Type ListBox}">
<Setter Property="Foreground" Value="White" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBox}">
<ScrollViewer x:Name="sv1" VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Hidden">
<Border
Height="100"
Padding="5"
BorderThickness="0.5"
CornerRadius="6"
VerticalAlignment="Center"
HorizontalAlignment="Center">
<StackPanel
IsItemsHost="True"
Orientation="Horizontal"
VerticalAlignment="Center"
HorizontalAlignment="Center" />
<Border.BorderBrush>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Offset="0" Color="#88000000"/>
<GradientStop Offset="1" Color="#DDFFFFFF"/>
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Border.BorderBrush>
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Offset="0" Color="#CCFFFFFF"/>
<GradientStop Offset="1" Color="#55FFFFFF"/>
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Border.Background>
</Border>
</ScrollViewer>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
.........
<ListBox
Grid.Row="2" Grid.ColumnSpan="2"
Margin="0,5,0,5"
Name="PhotosListBox"
DataContext="{Binding Source={StaticResource Icons}}"
ItemsSource="{Binding }"
SelectedIndex="0" />
..........

<Button x:Name="Left" Grid.Column="1" Grid.Row="1" Content="Left" Click="svLeft"/>
<Button x:Name="Right" Grid.Column="2" Grid.Row="1" Content="Right" Click="svRight"/>

Page1.xaml.cs

private void svRight(object sender, RoutedEventArgs e){
sv1.LineDown();
}
private void svUp(object sender, RoutedEventArgs e){
sv1.LineUp();
}



Answer this question

Access ScrollViewer from within a style

  • Wolf5

    Thanks for the above code guys!

    Just wondering has anyone expanded on this to allow the scrolling if the button is held down

    If not would anyone care to suggest a way

    Thanks

  • Kate Boothby

    Can someone explain how to implement the code given by Matt
  • wencey

    Genius.

    Now I've got to figure out how to databind this so I can have multiple PhotoListBoxs from an XML file


  • dr.acv

    Sorry, just have to replace the button with a repeatbutton
  • rWarrior

    ScrollViewer sv = VisualTreeHelper.GetChild(PhotosListBox, 0) as ScrollViewer;

    Then call your scroll commands

    sv.LineUp();

    sv.PageDown

    You will want to ensure that that returns a ScrollViewer and that it is not NULL. Depending on the style you create you may need to walk deeper in the VisualTree to find the actual ScrollViewer.



  • Ledeni_Plamen

    So there are a couple things ...

    - I am not sure what this is 'Client.BuddyList.PhotoListBox'.  In my code sample I reference PhotosListBox which is the name you gave the listbox in your markup.

    - In your scrolling methods, svRight and svLeft, you are calling LineUp and LineDown on a ScrollViewer that is stacking content horizontally.  You probably want to call LineRight and LineLeft.

    - In your ListBox style you have a tree structure like this

                 <ScrollViewer>

                            <Border>

                                        <StackPanel />

     This essentially means that the ScrollViewer really only has one item, the Border.   I would recommend moving the Border element outside the ScrollViewer.   You should get the same visual appearance, but you can now have better scrolling capabilities via the StackPanel, which implements IScrollInfo interface (which allows you to control logical vs. physical scrolling).

    If you do not want to change your style this code should retrieve the ScrollViewer for you.

    ScrollViewer scroll = VisualTreeHelper.GetChild(PhotosListBox, 0) as ScrollViewer;

    Just be sure that PhotoListBox is the name of the ListBox that you are referencing.

     If you do decide to change the order of elements in the style, which I recommend, you should be able to use this code or something similar.

            private ScrollViewer FindScroll()

            {

                Border scroll_border = VisualTreeHelper.GetChild(PhotosListBox, 0) as Border;

                if (scroll_border is Border)

                {

                    ScrollViewer scroll = scroll_border.Child as ScrollViewer;

     

                    if (scroll is ScrollViewer)

                    {

                        return scroll;

                    }

                    else

                    {

                        return null;

                    }

                }

                else

                {

                    return null;

                }

            }

            private void svRight(object sender, RoutedEventArgs e)

            {

                ScrollViewer sv = FindScroll();

     

                if (sv != null)

                    sv.LineRight();

                else

                    throw new Exception("Could not find ScrollViewer.");

            }

            private void svLeft(object sender, RoutedEventArgs e)

            {

                ScrollViewer sv = FindScroll();

     

                if (sv != null)

                    sv.LineLeft();

                else

                    throw new Exception("Could not find ScrollViewer.");

            }

            private void svDown(object sender, RoutedEventArgs e)

            {

                ScrollViewer sv = FindScroll();

     

                if (sv != null)

                    sv.LineDown();

                else

                    throw new Exception("Could not find ScrollViewer.");

            }

            private void svUp(object sender, RoutedEventArgs e)

            {

                ScrollViewer sv = FindScroll();

     

                if (sv != null)

                    sv.LineUp();

                else

                    throw new Exception("Could not find ScrollViewer.");

            }

     



  • l Bllizzd l

    I cleaned up FindScroll a little bit and made it usable by any DependencyObject:

    /// <summary>
    /// Retrieves the ScrollViewer object.
    /// </summary>
    /// <param name="listBox"></param>
    /// <returns></returns>

    public static ScrollViewer FindScroll( DependencyObject listBox )
    {
    Border scrollBorder = VisualTreeHelper.GetChild( listBox, 0 ) as Border;
    if ( scrollBorder == null ) return null;

    ScrollViewer scrollViewer = scrollBorder.Child as ScrollViewer;
    return scrollViewer;
    }



  • bw12117

    I gave that a try, but came up with "A field initializer cannot reference the nonstatic field, method, or property 'Client.BuddyList.PhotoListBox' "
  • dvdribeiro

    This is because the name is scoped to the style and not the window your buttons live in. If I'm not mistaken, you would need to reach into the visual tree of the ListBox to gain access to the ScrollViewer in order to manipulate it.

    HTH,
    Drew


  • Access ScrollViewer from within a style