【问题标题】:WPF ControlTemplate for scrolling TreeView Control用于滚动 TreeView 控件的 WPF ControlTemplate
【发布时间】:2008-10-28 21:26:38
【问题描述】:

我正在使用 TreeView 控件,当单击其中一个控件时,它会自动滚动到左对齐 TreeViewItem。我已经查看了我的样式和控件模板,但我没有找到任何东西。是否存在导致此问题的默认 ControlTemplate?我想禁用它。

【问题讨论】:

    标签: c# wpf


    【解决方案1】:

    项目滚动是因为 ScrollViewer 对它们调用了 BringIntoView()。因此,避免滚动的一种方法是抑制对 RequestBringIntoView 事件的处理。您可以通过继承 TreeView 并实例化此控件来快速尝试:

    public class NoScrollTreeView : TreeView
    {
        public class NoScrollTreeViewItem : TreeViewItem
        {
            public NoScrollTreeViewItem() : base()
            {
                this.RequestBringIntoView += delegate (object sender, RequestBringIntoViewEventArgs e) {
                    e.Handled = true;
                };
            }
    
            protected override DependencyObject GetContainerForItemOverride()
            {
                return new NoScrollTreeViewItem();
            }
        }
        protected override DependencyObject GetContainerForItemOverride()
        {
            return new NoScrollTreeViewItem();
        }
    }
    

    【讨论】:

      【解决方案2】:

      在这个问题上花了几个小时后,我找到了一个适合我的解决方案。

      防止 TreeViewItem 上的 RequestBringIntoView 事件冒泡的解决方案是第一步。不幸的是,如果您以编程方式更改所选项目,这也会停止显示树视图项目

      yourtreeview.SelectedItem = yourtreeviewitem
      

      所以,对我来说,解决方案是修改treeview的controltemplate如下:

      <Style x:Key="{x:Type TreeView}" TargetType="TreeView">
              <Setter Property="OverridesDefaultStyle" Value="True" />
              <Setter Property="SnapsToDevicePixels" Value="True" />
              <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
              <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
              <Setter Property="Template">
                  <Setter.Value>
                      <ControlTemplate TargetType="TreeView">
                          <Border Name="Border" BorderThickness="0" Padding="0" Margin="1">
                              <ScrollViewer Focusable="False" CanContentScroll="False" Padding="0">
                                  <Components:AutoScrollPreventer Margin="0">
                                      <ItemsPresenter/>
                                  </Components:AutoScrollPreventer>
                              </ScrollViewer>
                          </Border>
                      </ControlTemplate>
                  </Setter.Value>
              </Setter>
          </Style>
      

      “autoscrollpreventer”是:

      using System;
      using System.Windows;
      using System.Windows.Controls;
      
      namespace LiveContext.Designer.GUI.Components {
          public class AutoScrollPreventer : StackPanel
          {
          public AutoScrollPreventer() {
      
              this.RequestBringIntoView += delegate(object sender, RequestBringIntoViewEventArgs e)
              {
                  // stop this event from bubbling so that a scrollviewer doesn't try to BringIntoView..
                  e.Handled = true;
              };
      
          }
      }
      

      }

      希望对你有帮助..

      【讨论】:

        【解决方案3】:

        看来我在MSDN找到了一个很好的线索:

        听起来这是一种互动 使用滚动查看器和焦点 系统。

        当一个元素聚焦在一个 ScrollViewer(它是 TreeView 模板),ScrollViewer 被指示制作元素 可见的。它会自动响应 滚动到请求的元素。

        ScrollViewer 内部的方法 处理这些焦点请求的是 所有私人和/或内部所以你 真的无法接近他们。我不 认为你可以做的太多了 这个案例;这就是焦点的工作原理。

        那么,是这样吗?当然有一种方法可以修改 TreeView 模板,这样 ScrollViewer 就不会出现这种行为......

        【讨论】:

          【解决方案4】:

          好的,我终于可以得到这样的默认样式了:

                  using (Stream sw = File.Open(@"C:\TreeViewDefaults.xaml", FileMode.Truncate, FileAccess.Write))
                  {
                      Style ts = Application.Current.FindResource(typeof(TreeView)) as Style;
                      if (ts != null)
                          XamlWriter.Save(ts, sw);
                  }
          

          生产者:

          <Style TargetType="TreeView" 
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
                 xmlns:s="clr-namespace:System;assembly=mscorlib" 
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
              <Style.Triggers>
                  <Trigger Property="VirtualizingStackPanel.IsVirtualizing">
                      <Setter Property="ItemsControl.ItemsPanel">
                          <Setter.Value>
                              <ItemsPanelTemplate><VirtualizingStackPanel IsItemsHost="True" /></ItemsPanelTemplate>
                          </Setter.Value>
                      </Setter>
                      <Trigger.Value>
                          <s:Boolean>True</s:Boolean>
                      </Trigger.Value>
                  </Trigger>
              </Style.Triggers>
              <Style.Resources>
                  <ResourceDictionary />
              </Style.Resources>
              <Setter Property="Panel.Background">
                  <Setter.Value><DynamicResource ResourceKey="{x:Static SystemColors.WindowBrushKey}" /></Setter.Value>
              </Setter>
              <Setter Property="Border.BorderBrush">
                  <Setter.Value><SolidColorBrush>#FF828790</SolidColorBrush></Setter.Value>
              </Setter>
              <Setter Property="Border.BorderThickness">
                  <Setter.Value><Thickness>1,1,1,1</Thickness></Setter.Value>
              </Setter>
              <Setter Property="Control.Padding">
                  <Setter.Value><Thickness>1,1,1,1</Thickness></Setter.Value>
              </Setter>
              <Setter Property="TextElement.Foreground">
                  <Setter.Value><DynamicResource ResourceKey="{x:Static SystemColors.ControlTextBrushKey}" /></Setter.Value>
              </Setter>
              <Setter Property="ScrollViewer.HorizontalScrollBarVisibility">
                  <Setter.Value><x:Static Member="ScrollBarVisibility.Auto" /></Setter.Value>
              </Setter>
              <Setter Property="ScrollViewer.VerticalScrollBarVisibility">
                  <Setter.Value><x:Static Member="ScrollBarVisibility.Auto" /></Setter.Value>
              </Setter>
              <Setter Property="Control.VerticalContentAlignment">
                  <Setter.Value><x:Static Member="VerticalAlignment.Center" /></Setter.Value>
              </Setter>
              <Setter Property="Control.Template">
                  <Setter.Value>
                      <ControlTemplate TargetType="TreeView">
                          <Border BorderThickness="{TemplateBinding Border.BorderThickness}" 
                                  BorderBrush="{TemplateBinding Border.BorderBrush}" 
                                  Name="Bd" SnapsToDevicePixels="True">
                              <ScrollViewer CanContentScroll="False" 
                                            HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}" 
                                            VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}" 
                                            Background="{TemplateBinding Panel.Background}" 
                                            Padding="{TemplateBinding Control.Padding}" 
                                            Name="_tv_scrollviewer_" 
                                            SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" 
                                            Focusable="False">
                                  <ItemsPresenter />
                              </ScrollViewer>
                          </Border>
                          <ControlTemplate.Triggers>
                              <Trigger Property="UIElement.IsEnabled">
                                  <Setter Property="Panel.Background" TargetName="Bd">
                                      <Setter.Value>
                                          <DynamicResource ResourceKey="{x:Static SystemColors.ControlBrushKey}" />
                                      </Setter.Value>
                                  </Setter>
                                  <Trigger.Value>
                                      <s:Boolean>False</s:Boolean>
                                  </Trigger.Value>
                              </Trigger>
                              <Trigger Property="VirtualizingStackPanel.IsVirtualizing">
                                  <Setter Property="ScrollViewer.CanContentScroll" TargetName="_tv_scrollviewer_">
                                      <Setter.Value><s:Boolean>True</s:Boolean></Setter.Value>
                                  </Setter>
                                  <Trigger.Value>
                                      <s:Boolean>True</s:Boolean>
                                  </Trigger.Value>
                              </Trigger>
                          </ControlTemplate.Triggers>
                      </ControlTemplate>
                  </Setter.Value>
              </Setter>
          </Style>
          

          不幸的是,这看起来没有帮助。我没有看到任何用于停止自动滚动焦点的属性。

          还在寻找……

          【讨论】:

            【解决方案5】:

            另一个有趣的花絮:有一个名为 HandlesScrolling 的可覆盖布尔值,它总是返回 true。反编译源代码后,看起来这个属性从未使用过(或者它正在 XAML 中的某个深、暗、秘密的地方使用)。我尝试制作自己的 TreeView 控件来将此值设置为 false,但它不起作用。

            【讨论】:

            • 不错。我想我们可以涉足 .NET 源代码,但是……你知道的。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-10-23
            • 2010-12-06
            • 1970-01-01
            • 2011-08-16
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多