Подтвердить что ты не робот

WPF TreeView - как прокручивается такая расширенная ветвь

Когда я расширяю элементы в своем древовидной структуре, чтобы прокрутка была необходима, появляется полоса прокрутки. Однако он не прокручивается вниз для недавно расширенной ветки элементов - они обрезаются нижней частью элемента управления. Так как я продолжаю расширять элементы в нижней части дерева, я должен вручную прокручивать вниз, чтобы увидеть новых детей. У кого-нибудь есть предложение, как заставить его автоматически прокручивать, чтобы показать недавно расширенные элементы?

4b9b3361

Ответ 1

В TreeView обработайте событие TreeViewItem.Expanded(вы можете сделать это на уровне TreeView из-за пузырьков событий). В расширенном обработчике вызовите BringIntoView в TreeViewItem, который вызвал событие.

Вам может понадобиться немного проб и ошибок, чтобы получить TreeViewItem в коде обработчика событий. Я думаю, что (не проверял), что аргументом отправителя для вашего обработчика расширенных событий будет TreeView (с тех пор, как он привязан к обработчику события), а не TreeViewItem. И e.Source или e.OriginalSource может быть элементом в шаблоне данных TreeViewItem. Поэтому вам может понадобиться использовать VisualTreeHelper, чтобы подойти к визуальному дереву, чтобы найти TreeViewItem. Но если вы используете отладчик для проверки отправителя и RoutedEventArgs, это должно быть тривиально, чтобы выяснить.

(Если вы можете заставить это работать и хотите его объединить, вам не нужно прикреплять один и тот же обработчик событий к каждому TreeView, он должен быть легко инкапсулировать его как прикрепленное поведение, которое позволит вам применять его декларативно, в том числе через стиль.)

Ответ 2

Вы можете использовать простой стиль EventSetter в стиле TreeViewItem для вызова обработчика события, когда элемент выбран. Затем вызовите BringIntoView для элемента.

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

</TreeView>

private void TreeViewSelectedItemChanged(object sender, RoutedEventArgs e)
{
    TreeViewItem item = sender as TreeViewItem;
    if (item != null)
    {
        item.BringIntoView();
        e.Handled = true;  
    }
}

Ответ 3

Используйте свойство зависимости на триггере IsSelected:

<Style TargetType="{x:Type TreeViewItem}">
 <Style.Triggers>
  <Trigger Property="IsSelected" Value="True">
    <Setter Property="commands:TreeViewItemBehavior.BringIntoViewWhenSelected" Value="True" />
  </Trigger>
</Style.Triggers>

Здесь код для свойства зависимостей:

public static bool GetBringIntoViewWhenSelected(TreeViewItem treeViewItem)
{
  return (bool)treeViewItem.GetValue(BringIntoViewWhenSelectedProperty);
}

public static void SetBringIntoViewWhenSelected(TreeViewItem treeViewItem, bool value)
{
  treeViewItem.SetValue(BringIntoViewWhenSelectedProperty, value);
}

public static readonly DependencyProperty BringIntoViewWhenSelectedProperty =
    DependencyProperty.RegisterAttached("BringIntoViewWhenSelected", typeof(bool),
    typeof(TreeViewItemBehavior), new UIPropertyMetadata(false, OnBringIntoViewWhenSelectedChanged));

static void OnBringIntoViewWhenSelectedChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs e)
{
  TreeViewItem item = depObj as TreeViewItem;
  if (item == null)
    return;

  if (e.NewValue is bool == false)
    return;

  if ((bool)e.NewValue)
    item.BringIntoView();
}

Ответ 4

Благодаря ответу itowlson, здесь расширенный код обработчика событий, который работает для обоих моих деревьев

private static void Tree_Expanded(object sender, RoutedEventArgs e)
{
    // ignore checking, assume original source is treeviewitem
    var treeViewItem = (TreeViewItem)e.OriginalSource;

    var count = VisualTreeHelper.GetChildrenCount(treeViewItem);

    for (int i = count - 1; i >= 0; --i)
    {
        var childItem = VisualTreeHelper.GetChild(treeViewItem, i);
        ((FrameworkElement)childItem).BringIntoView();
    }

    // do NOT call BringIntoView on the actual treeviewitem - this negates everything
    //treeViewItem.BringIntoView();
}