none
Access ScrollViewer from within a style RRS feed

  • Question

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

     

    Tuesday, December 5, 2006 7:00 PM

Answers

  • 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.");

            }

     

    Wednesday, December 6, 2006 7:19 PM

All replies

  • 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

    Tuesday, December 5, 2006 9:33 PM
    Moderator
  • 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.

    Wednesday, December 6, 2006 12:14 AM
  • I gave that a try, but came up with "A field initializer cannot reference the nonstatic field, method, or property 'Client.BuddyList.PhotoListBox' "
    Wednesday, December 6, 2006 12:30 AM
  • Can someone explain how to implement the code given by Matt?
    Wednesday, December 6, 2006 1:52 PM
  • 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.");

            }

     

    Wednesday, December 6, 2006 7:19 PM
  • Genius.

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

    Wednesday, December 6, 2006 10:21 PM
  • 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
    Wednesday, May 16, 2007 9:37 PM
  • Sorry, just have to replace the button with a repeatbutton
    Thursday, May 17, 2007 11:00 AM
  • 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;
            }


    Wednesday, December 5, 2007 8:25 PM