Prevent Automatic Horizontal Scroll in TreeView

前端 未结 8 911
伪装坚强ぢ
伪装坚强ぢ 2020-12-14 06:41

Whenever a node is selected in my treeview, it automatically does a horizontal scroll to that item. Is there a way to disable this?

相关标签:
8条回答
  • 2020-12-14 07:21

    I had a DataGrid that I wanted to do the same operation on and used POHB's answer mostly. I had to modify it for my solution. The code is shown below. The datagrid is a 2 x 2 datagrid with the first column being thin and the second being very wide (1000+). The first column is frozen. I hope this helps someone out. -Matt

      public partial class MyUserControl : UserControl
      {
          private ScrollContentPresenter _scrollContentPresenter;
          private ScrollViewer _scrollViewer;
          private double _dataGridHorizScrollPos = 0.0;
          private bool _dataGridResetHorizScroll = false;
    
          public MyUserControl()
          {
              // setup code...
              _dataGrid.ApplyTemplate();
    
              _scrollViewer = FindVisualChild<ScrollViewer>(_dataGrid);
              _scrollViewer.ScrollChanged += new ScrollChangedEventHandler(DataGridScrollViewerScrollChanged);
    
              _scrollContentPresenter = FindVisualChild<ScrollContentPresenter>(_scrollViewer);
              _scrollContentPresenter.RequestBringIntoView += new RequestBringIntoViewEventHandler(_scrollContentPresenter_RequestBringInputView);              
          }
    
          private void DataGridScrollViewerScrollChanged(object sender, ScrollChangedEventArgs e)
          {
              if (_dataGridResetHorizScroll)
              {
                  _scrollViewer.ScrollToHorizontalOffset(_dataGridHorizScrollPos);
              }
              // Note: When the row just before a page change is selected and then the next row on the  
              // next page is selected, a second event fires setting the horizontal offset to 0
              // I'm ignoring those large changes by only recording the offset when it's large. -MRB
              else if (Math.Abs(e.HorizontalChange) < 100)
              {
                  _dataGridHorizScrollPos = _scrollViewer.HorizontalOffset;
              }
    
              _dataGridResetHorizScroll = false;
          }
    
          public T FindVisualChild<T>(DependencyObject depObj) where T : DependencyObject
          {
              if (depObj != null)
              {
                  for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
                  {
                      DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
    
                      if ((child != null) && (child is ScrollViewer))
                      {
                          // I needed this since the template wasn't applied yet when 
                          // calling from  the constructor
                          (child as ScrollViewer).ApplyTemplate();
                      }
    
                      if (child != null && child is T)
                      {
                          return (T)child;
                      }
    
                      T childItem = FindVisualChild<T>(child);
                      if (childItem != null) return childItem;
                  }
              }
              return null;
          }
    
          private void _scrollContentPresenter_RequestBringInputView(object sender, RequestBringIntoViewEventArgs e)
          {
              _dataGridResetHorizScroll = true;
          }
    
    0 讨论(0)
  • 2020-12-14 07:22

    To offer a slightly simplified version of @lena's answer:

    To scroll vertically while preserving the horizontal scroll position, and with no unwanted side effects, in the XAML, add event handlers for RequestBringIntoView and Selected:

    <TreeView>
        <TreeView.ItemContainerStyle>
            <Style TargetType="{x:Type TreeViewItem}">
                <EventSetter Event="RequestBringIntoView" Handler="TreeViewItem_RequestBringIntoView"/>
                <EventSetter Event="Selected" Handler="OnSelected"/>
                ...
    

    In the code behind, add two event handlers:

    private void TreeViewItem_RequestBringIntoView(object sender, RequestBringIntoViewEventArgs e)
    {
        // Ignore re-entrant calls
        if (mSuppressRequestBringIntoView)
            return;
    
        // Cancel the current scroll attempt
        e.Handled = true;
    
        // Call BringIntoView using a rectangle that extends into "negative space" to the left of our
        // actual control. This allows the vertical scrolling behaviour to operate without adversely
        // affecting the current horizontal scroll position.
        mSuppressRequestBringIntoView = true;
    
        TreeViewItem tvi = sender as TreeViewItem;
        if (tvi != null)
        {
            Rect newTargetRect = new Rect(-1000, 0, tvi.ActualWidth + 1000, tvi.ActualHeight);
            tvi.BringIntoView(newTargetRect);
        }
    
        mSuppressRequestBringIntoView = false;
    }
    private bool mSuppressRequestBringIntoView;
    
    // Correctly handle programmatically selected items
    private void OnSelected(object sender, RoutedEventArgs e)
    {
        ((TreeViewItem)sender).BringIntoView();
        e.Handled = true;
    }
    
    0 讨论(0)
提交回复
热议问题