GridViewHeaderRowPresenter使用自定义TreeListView控件滚动

时间:2015-02-19 11:21:02

标签: wpf gridviewheader

我有一个基于标准TreeView的自定义TreeListView - 具有以下样式:

<Style TargetType="{x:Type c:TreeListView}">
   <Setter Property="Template">
      <Setter.Value>
         <ControlTemplate TargetType="{x:Type: c:TreeListView}">
            <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
               <DockPanel>
                  <GridViewHeaderRowPresenter DockPanel.Dock="Top" Columns="{Binding Path=Columns, RelativeSource={RelativeSource TemplatedParent}}" />
                  <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
               </DockPanel>
            </Border>
         </ControlTemplate>
      </Setter.Value>
   </Setter>
</Style>

因为我没有ScrollViewer,所以内容不会滚动,所以如果内容需要的空间比可用空间多,它看起来像这样:

enter image description here

所以我添加了一个ScrollViewer,以便样式现在看起来像这样:

<Style TargetType="{x:Type c:TreeListView}">
   <Setter Property="Template">
      <Setter.Value>
         <ControlTemplate TargetType="{x:Type: c:TreeListView}">
            <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
               <ScrollViewer Focusable="False" Padding="{TemplateBinding Padding">
                  <DockPanel>
                     <GridViewHeaderRowPresenter DockPanel.Dock="Top" Columns="{Binding Path=Columns, RelativeSource={RelativeSource TemplatedParent}}" />
                     <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                  </DockPanel>
               </ScrollViewer>
            </Border>
         </ControlTemplate>
      </Setter.Value>
   </Setter>
</Style>

随着内容在第一张图片中展开,内容无法滚动,但列标题也会出现问题,这是不希望的:D

enter image description here

有人可以帮助我,以便只滚动内容,而不是绑定到 GridViewHeaderRowPresenter 的列吗?

谢谢!

[编辑]

感谢右边的相关链接,我找到了答案here

而不是 ScrollViewer 中的 DockPanel ,我只需要在 ScrollViewer 中包含 ItemsPresenter 。所以使用以下 Style 它现在可以使用。

<Style TargetType="{x:Type c:TreeListView}">
   <Setter Property="Template">
      <Setter.Value>
         <ControlTemplate TargetType="{x:Type c:TreeListView}">
            <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
               <DockPanel>
                  <GridViewHeaderRowPresenter DockPanel.Dock="Top" Columns="{Binding Path=Columns, RelativeSource={RelativeSource TemplatedParent}}" />
                  <ScrollViewer Focusable="False" Padding="{TemplateBinding Padding}">
                     <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                  </ScrollViewer>
               </DockPanel>
            </Border>
         </ControlTemplate>
      </Setter.Value>
   </Setter>
</Style>

非常感谢Nikhil Agrawal的代码!

2 个答案:

答案 0 :(得分:0)

给出的解决方案是不完整的,只有在你有一个固定的宽度控制时才会起作用。仅包装ItemsPresenter标题列将不会在需要时水平滚动。这会导致值列移位,然后标题不匹配。

我已尝试将SelectiveScrollingGrid.SelectiveScrollingOrientation="Horizontal"应用于GridViewHeaderRowPresenter但尚未成功使用该方法。

相反,您可以向GridViewHeaderRowPresenterItemsPresenter添加滚动查看器,然后将它们同步。它不是最好的解决方案,但至少它可行。

<Style TargetType="{x:Type local:TreeListView}">
<Setter Property="Template">
    <Setter.Value>
        <ControlTemplate TargetType="{x:Type local:TreeListView}">
            <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
                <DockPanel>
                    <ScrollViewer DockPanel.Dock="Top"
                                  HorizontalScrollBarVisibility="Hidden"
                                  Name="scrollViewerHeader"
                                  VerticalScrollBarVisibility="Disabled">
                        <GridViewHeaderRowPresenter Columns="{StaticResource gvcc}"/>
                    </ScrollViewer>
                    <ScrollViewer HorizontalScrollBarVisibility="Auto"
                                  Name="scrollViewerBody"
                                  VerticalScrollBarVisibility="Auto">
                        <ItemsPresenter />
                    </ScrollViewer>
                </DockPanel>
            </Border>
        </ControlTemplate>
    </Setter.Value>
</Setter>

背后的代码:

public class TreeListView : TreeView
{
    private ScrollViewer _scrollViewerHeader;
    private ScrollViewer _scrollViewerBody;

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        _scrollViewerHeader = (ScrollViewer)Template.FindName("scrollViewerHeader", this);
        _scrollViewerBody = (ScrollViewer)Template.FindName("scrollViewerBody", this);

        _scrollViewerBody.ScrollChanged += (sender, e) =>
                                            {
                                                _scrollViewerHeader.Width = e.ViewportWidth;
                                                _scrollViewerHeader.ScrollToHorizontalOffset(e.HorizontalOffset);
                                            };
    }
}

答案 1 :(得分:0)

DataGrid解决问题的方法是自定义ScrollViewer的模板,将GridViewHeaderRowPresenter放在ScrollViewer ScrollContentPresenter之外:

https://github.com/dotnet/wpf/blob/059ba38771aef10d2172a3ca0e247dfbfa8cefde/src/Microsoft.DotNet.Wpf/src/Themes/PresentationFramework.Aero2/Themes/Aero2.NormalColor.xaml#L987-L993

这样,当滚动条滚动时,它们不会影响标题行。

使用ListView的{​​{1}}在这里做类似的事情: https://github.com/dotnet/wpf/blob/059ba38771aef10d2172a3ca0e247dfbfa8cefde/src/Microsoft.DotNet.Wpf/src/Themes/PresentationFramework.Aero2/Themes/Aero2.NormalColor.xaml#L2628

同时,他们将标题行包装在另一个GridView中,老实说,我不明白为什么。

一旦我发现更多信息,我将继续回答这个问题。我认为这种方法比同步滚动查看器更干净。