Когда я расширяю элементы в своем древовидной структуре, чтобы прокрутка была необходима, появляется полоса прокрутки. Однако он не прокручивается вниз для недавно расширенной ветки элементов - они обрезаются нижней частью элемента управления. Так как я продолжаю расширять элементы в нижней части дерева, я должен вручную прокручивать вниз, чтобы увидеть новых детей. У кого-нибудь есть предложение, как заставить его автоматически прокручивать, чтобы показать недавно расширенные элементы?
WPF TreeView - как прокручивается такая расширенная ветвь
Ответ 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();
}