简体   繁体   中英

WPF accessing scrollviewer of a listview codebehind

I need to access the scrollviewer of a listview from the codebehind. here is the definition of my listview

<ListView Grid.Row="1" ItemsSource="{Binding Path=SpecList, UpdateSourceTrigger=PropertyChanged}"  
                            Name="mylistview"
                            ItemTemplate="{StaticResource SpecElementTemplate}"
                            Background="{StaticResource EnvLayout}"
                            ScrollViewer.HorizontalScrollBarVisibility="Visible"
                            ScrollViewer.VerticalScrollBarVisibility="Disabled"
                            ItemContainerStyle="{StaticResource MyStyle}"
                            BorderBrush="Blue"
                            BorderThickness="20"
                            Margin="-2">
    <ListView.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal" />
        </ItemsPanelTemplate>
    </ListView.ItemsPanel>
</ListView>

How can I get the scrollviewer?

Thank you

Andrea

There are several ways to get the ScrollViewer . Simplest solution is to get the the first child of the first child of the ListView . This means get the Border and the ScrollViewer inside this Border like described in this answer :

// Get the border of the listview (first child of a listview)
Decorator border = VisualTreeHelper.GetChild(mylistview, 0) as Decorator;

// Get scrollviewer
ScrollViewer scrollViewer = border.Child as ScrollViewer;

A second way is to scan all childrens recursive to find the ScrollViewer. This is described in the answer by Matt Hamilton in this question . You can simply use this function to get the ScrollViewer .

ScrollViewer scrollViewer = GetChildOfType<ScrollViewer>(mylistview);

This second solution is much more generic and will also work if the template of your ListView was edited.

Use VisualTreeHelper class to access any child control.

Psudeo code to your case:

 //Declare a scroll viewer object.
 ScrollViewer  sViewer = default(ScrollViewer );

 //Start looping the child controls of your listview.
 for (int i = 0; i < VisualTreeHelper.GetChildrenCount(YOUR_LISTVIEW_OBJECT.VisualParent ); i++)
 {
        // Retrieve child visual at specified index value.
        Visual childVisual = (Visual)VisualTreeHelper.GetChild(YOUR_LISTVIEW_OBJECT.VisualParent , i);

        ScrollViewer sViewer = childVisual as ScrollViewer;

        //You got your scroll viewer. Stop looping.
         if (sViewer != null)
         {
             break;
         }      
 }

我不知道您为什么要访问scrollviewer,但它是一个附加属性和附加属性,您可以这样设置: 如何在代码后面访问附加属性?

I also suggest using the CollectionChanged event. In this code, the CollectionChanged event handler is added to the codebehind after the view model has been loaded. Then, each time the collection changes we scroll to the bottom of the listview. Here is an important point. The scrollviewer child of the list view might not yet be completely rendered when our events start firing. Hence we will get exceptions if we try to use the VisualTreeHelper.GetChild method. So, we have to first attempt to get the scrollviewer and then ignore its positioning if it is not yet available.

private void ReceivedItems_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        // Make sure the items source property in the viewmodel has some items
        if (myViewModel.ReceivedItems.Count > 0)
        {
            var aScrollViewer = RcvdListView.GetChildOfType<ScrollViewer>();
            // Make sure the scrollviewer exists before trying to position it
            if (aScrollViewer != null)
            {
                aScrollViewer.ScrollToBottom();
            }
        }
    }


    

Listview's ScrollViewer should be accessible after LayoutUpdated . You could hook on LayoutUpdated and then get if from Visual tree

 private static void ListView_LayoutUpdated(object sender, EventArgs e)
 {
    var listview = (ListView)sender;
    var viewer = listview.GetFirstChildOfType<ScrollViewer>();
 }

public static T GetFirstChildOfType<T>(this DependencyObject dependencyObject) where T : DependencyObject
    {
      if (dependencyObject == null)
      {
        return null;
      }

      for (var i = 0; i < VisualTreeHelper.GetChildrenCount(dependencyObject); i++)
      {
        var child = VisualTreeHelper.GetChild(dependencyObject, i);

        var result = (child as T) ?? GetFirstChildOfType<T>(child);

        if (result != null)
        {
          return result;
        }
      }

      return null;
    }

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