Невозможно предотвратить автоматическую горизонтальную прокрутку в TreeView в базовом классе при выборе элемента в Silverlight

#silverlight #silverlight-4.0 #silverlight-toolkit

#silverlight #silverlight-4.0 #silverlight-toolkit

Вопрос:

Я пытаюсь предотвратить автоматическую горизонтальную прокрутку элемента древовидного представления при выборе его в Silverlight. И я пытаюсь сделать это в базовом классе.

До сих пор я не мог с этим справиться. Я попробовал следующий код, но он выполняется, а затем вещь все равно прокручивается, когда я ее выбираю.

 using System.Windows;
using System.Windows.Controls;

namespace MyControls
{
    public class CustomTreeView : TreeView
    {
        private ScrollViewer _scrollViewer;

        protected override void OnSelectedItemChanged(RoutedPropertyChangedEventArgs<object> e)
        {
            base.OnSelectedItemChanged(e);
            _scrollViewer.ScrollToHorizontalOffset(0);
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            _scrollViewer = GetTemplateChild("ScrollViewer") as ScrollViewer;
        }
    }
}
  

На самом деле я не хочу полностью отключать прокрутку — если элемент вылетает за пределы древовидного представления, я хочу, чтобы пользователь мог прокручивать его. Что я пытаюсь сделать, так это сохранить дерево там, где оно есть, когда я выбираю дочерний узел, который может быть длиннее ширины экрана.

Я пробовал RequestBringIntoView на WrapPanel, но, похоже, это только для WPF. Я также пытался сделать это в UpdateLayout, а также в SelectedItemChanged. Все безрезультатно. Кажется, я не могу найти общее решение, от которого я мог бы унаследовать и использовать другой класс.

У кого-нибудь есть идеи?

Спасибо!

-Ari

РЕДАКТИРОВАТЬ: в вознаграждении указано, что мне нужно иметь возможность делать это в XAML. Это была опечатка с моей стороны. Я также приму кодовые решения. Спасибо!

Ответ №1:

Что вызывает ScrollViewer прокрутку, так это то, что каждый раз TreeView , когда изменяется выбор, ScrollIntoView вызывается a (внутри TreeView исходного кода),

 this.ItemsControlHelper.ScrollIntoView(container.HeaderElement ?? container);
  

и он в основном пытается прокрутить либо заголовок, либо весь TreeViewItem текст до самого левого края. Сначала я подумал, что вы можете изменить оба TreeView TreeViewItem стиля и, удалив все левое Margin и сделав заголовок с тем же левым полем, что и кнопка расширения. Однако это решение работает только для элементов первого уровня, так как на втором уровне перед элементом есть отступ, поэтому, если вы нажмете на него, он снова будет прокручиваться.

Так что, я думаю, чистого решения xaml не существует. Самым простым способом решения этой проблемы было бы, учитывая, что у вас уже есть пользовательский элемент управления, вместо вызова (я думаю, что есть проблема с синхронизацией, и именно поэтому этот код не работает)

 _scrollViewer.ScrollToHorizontalOffset(0); 
  

вы делаете

 var scrollableRegions = _scrollViewer.GetVisualDescendants().OfType<IScrollInfo>();
            foreach (var region in scrollableRegions)
            {
                region.SetHorizontalOffset(0);
            }
  

Если вы действительно предпочитаете решения xaml, вы также можете поместить этот код в поведение или прикрепленное свойство и просто добавить его с помощью Blend.

Сказав все это, другое решение, которое я лично считаю лучшим и использовал его в своем собственном приложении, — полностью отключить горизонтальную полосу прокрутки и использовать TextTrimming="WordEllipsis" для all my TextBlocks inside TreeViewItems , чтобы указать пользователю, что текста больше. Также укажите GridSplitter , чтобы пользователь мог изменять размер TreeView содержимого, чтобы видеть полный текст, вместо прокрутки вперед и назад по горизонтали. Но это только мое мнение.

Надеюсь, это поможет! 🙂

Комментарии:

1. @AriRoth, рад помочь. 🙂 не могли бы вы также выделить мне бонусные баллы? Спасибо…

2. Выполнено. Я никогда раньше не назначал награду, поэтому я не понимал, что для этого мне нужно нажать отдельную кнопку. 🙂

Ответ №2:

Поздний ответ для тех, кто не удовлетворен решениями, приведенными выше:

Как объясняется в этом блоге разработчиков MSDN, древовидное представление прокручивается, потому что TreeViewItem вызывает свой метод BringIntoView при выборе. Событие можно отменить, переопределив его обработчик и пометив его как обработанное следующим образом:

XAML:

 <TreeView>
  <TreeView.Resources>
    <Style TargetType="TreeViewItem">
      <EventSetter Event="RequestBringIntoView" Handler="TreeViewItem_RequestBringIntoView"/>
    </Style>
  </TreeView.Resources>
</TreeView>
  

обработчик:

 void TreeViewItem_RequestBringIntoView(object sender, RequestBringIntoViewEventArgs e) {
  e.Handled = true;
}
  

У подхода есть недостаток: прямые вызовы также tvi.BringIntoView() перестают работать, но его можно обойти, установив логический флаг перед вызовом BringIntoView , проверив его в обработчике и сбросив его после вызова.

Ответ №3:

Я думаю, что в вашем случае лучший способ добиться этого — полностью убрать средство просмотра прокрутки внутри древовидного представления, создав простой стиль древовидного представления, подобный этому:

     <Style x:Key="TreeViewStyle1" TargetType="sdk:TreeView">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="sdk:TreeView">
                    <Grid>
                        <ItemsPresenter Margin="5,5,19,19" d:LayoutOverrides="Width, Height"/>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
  

Затем просто примените шаблон к вашему средству просмотра прокрутки и оберните его внешним средством просмотра прокрутки таким образом:

 <Grid x:Name="LayoutRoot" DataContext="{Binding Source={StaticResource TreeViewSampleData}}">
    <ScrollViewer>
        <sdk:TreeView ItemsSource="{Binding RootCollection}" ItemTemplate="{StaticResource FirstLevelTemplate}" Style="{StaticResource TreeViewStyle1}"/>
    </ScrollViewer>
</Grid>
  

Теперь древовидное представление не имеет возможности взаимодействовать со средством просмотра прокрутки и, следовательно, не сможет прокручивать при выборе элемента.

Имейте в виду, что это исключает любую автоматическую прокрутку, и теперь возможна только ручная прокрутка. Вы все равно можете добавить свою собственную автоматическую прокрутку, используя поведение или TargetedTriggerAction (ы) .

Убедитесь, что вы не устанавливаете какие-либо размеры в древовидном представлении, чтобы оно свободно росло внутри средства просмотра прокрутки.

Надеюсь, это поможет.