在水平滚动时,保持树视图的最左列可见

Fre*_*ric 21 c# wpf

我使用ControlTemplate和GridViewRowPresenter的堆栈面板在WPF中实现了一个带有列的树视图.我按照这篇文章:http://blogs.msdn.com/b/atc_avalon_team/archive/2006/03/01/541206.aspx

它完美无缺!

但是,我希望在水平滚动时保持左列(带名称)可见.

这就像第一列上的microsoft excel上的'冻结窗格'.

一个想法,任何人?

谢谢弗雷德里克

Joe*_*ant 5

该解决GridViewRowPresenter方案的问题在于树与其他列不可分割.我认为你需要它是独立的,这样你就可以将水平仅ScrollViewer放在列的周围,我怀疑这对你链接的文章中的项目很容易(如果可能的话).

这个项目,我一起打算弄清楚的东西是非常粗糙的边缘.您需要单独解决许多问题我没有进行微调:

  1. 模板和样式使线条匹配,以及其他视觉调整.
  2. 重新介绍GridView标题和列的链接项目的各个方面.
  3. 用于调整第一列(包含树)大小的分离器.

与文章项目一样,我使用了一个Type对象树作为数据源.

让这个工作的关键是将数据对象包装在一个ExpandingContainer对象中.这个INPC类的重要内容是IsExpanded属性(用于绑定)和子集合:

public class ExpandingContainer : INotifyPropertyChanged {
    public object Payload { get; private set; }

    public ObservableCollection<ExpandingContainer> Children { get; private set; }

    public ExpandingContainer( object payload ) { ... }

    private bool _isexpanded;
    public bool IsExpanded {
        get { return _isexpanded; }
        set {
            if ( value == _isexpanded )
                return;
            _isexpanded = value;
            PropertyChanged.Notify( () => IsExpanded );
        }
    }

    public event PropertyChangedEventHandler PropertyChanged = (o,e) => {};
}
Run Code Online (Sandbox Code Playgroud)

至于XAML,首先让我们获取一些资源:

<!-- bind ExpandingContainer.IsExpanded to TreeViewItem.IsExpanded -->
<Style TargetType="TreeViewItem">
    <Setter Property="IsExpanded"
            Value="{Binding IsExpanded, Mode=TwoWay}" />
</Style>

<!-- for binding ExpandingContainer.IsExpanded to visibility later -->
<BooleanToVisibilityConverter x:Key="boolvis" />

<!-- the TreeViewItems should display the Type's name -->
<HierarchicalDataTemplate DataType="{x:Type loc:ExpandingContainer}"
                          x:Key="treeViewSide"
                          ItemsSource="{Binding Children}">
    <TextBlock Text="{Binding Payload.Name}" />
</HierarchicalDataTemplate>

<!-- the column side are naively simple, the ItemsControl of children has its
     visibility bound to ExpandingContainer, but the "columns" are just
     StackPanels of TextBlocks -->
<HierarchicalDataTemplate DataType="{x:Type loc:ExpandingContainer}"
                          x:Key="columnSide">
    <StackPanel>
        <StackPanel.Resources>
            <Style TargetType="TextBlock">
                <Setter Property="Margin" Value="10,0" />
            </Style>
        </StackPanel.Resources>
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="{Binding Payload.IsAbstract}" />
            <TextBlock Text="{Binding Payload.Namespace}" />
            <TextBlock Text="{Binding Payload.GUID}" />
        </StackPanel>
        <ItemsControl ItemsSource="{Binding Children}"
                      Visibility="{Binding IsExpanded, Converter={StaticResource boolvis}}" />
    </StackPanel>
</HierarchicalDataTemplate>

<!-- a style can't refer to itself, so this was just to apply it to all ItemsControls -->
<Style TargetType="ItemsControl">
    <Setter Property="ItemTemplate"
            Value="{StaticResource columnSide}" />
</Style>
Run Code Online (Sandbox Code Playgroud)

我本来试图嵌套水平仅ScrollViewer垂直仅含有内正确的列ScrollViewer,这是负责的TreeView,但产生的,你必须滚动至底部水平滚动奇怪的规定.所以我将它们进一步分开,并排放在一起ScrollViewer.

为了使垂直滚动条保持在最右边,我将两个滚动条隐藏在周围,TreeView并仅使用列周围的滚动条.同步垂直滚动是在代码隐藏中完成的,但是对于更多的MVVM方法,您可以创建一个附加行为以便于将它们相互绑定.

<DockPanel>
    <ScrollViewer VerticalScrollBarVisibility="Hidden"
                  HorizontalScrollBarVisibility="Hidden"
                  DockPanel.Dock="Left"
                  Name="treescroller">
        <TreeView ItemsSource="{Binding Items}"
                  ItemTemplate="{StaticResource treeViewSide}"
                  Padding="0,0,0,20">
        </TreeView>
    </ScrollViewer>
    <ScrollViewer Name="columnscroller"
                  HorizontalScrollBarVisibility="Auto"
                  VerticalScrollBarVisibility="Auto"
                  ScrollChanged="columnscroller_ScrollChanged">
        <ItemsControl ItemsSource="{Binding Items}" />
    </ScrollViewer>
</DockPanel>
Run Code Online (Sandbox Code Playgroud)

最后,代码隐藏的重要部分(减去数据对象和设置DataContext属性):

private void columnscroller_ScrollChanged( object sender, ScrollChangedEventArgs e ) {
    treescroller.ScrollToVerticalOffset( columnscroller.VerticalOffset );
}
Run Code Online (Sandbox Code Playgroud)

希望它有所帮助,或者至少提供不同的视角.

如果我真的需要一个满足我对混合动力TreeView+的所有需求的好的ListView,我可能会先花一些时间来研究专业控制,然后花费必要的时间来完善自己的解决方案.当这种显示的要求很简单时,这种情况会更好.