保持一个TreeView的最左列可见,而水平滚动 [英] Keep the leftmost column of a treeview visible while scrolling horizontally

查看:556
本文介绍了保持一个TreeView的最左列可见,而水平滚动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我实现了一个TreeView使用的ControlTemplate和GridViewRowPresenter的StackPanel的WPF中列。我跟着这篇文章: HTTP://blogs.msdn。 COM / b / atc_avalon_team /存档/ 2006/03/01 / 541206.aspx



它完美!



不过,我想保持左边的列(含名称)可见,而水平滚动。



这就像微软冻结窗格 Excel中的第一列。



这是想法,任何人?



由于
弗雷德里克


解决方案

GridViewRowPresenter 解决方案的问题是,这棵树是从另一个不可分割的列。我想你需要它是独立的,这样就可以把水平仅的ScrollViewer 绕柱,我怀疑这是很容易(如果可能)做项目在您链接的文章。



这项目,我拼凑推测出来的东西是周围的边缘相当粗糙。有一些问题,你需要分别制定出我没微调:




  1. 模板和样式,使线投其所好,和其他视觉调整。

  2. 重新引入链接项目为标题和列中的 GridView控件的方面。
  3. ,一种用于调整第一列的大小(包含树)分离器。



  4. 像文章项目,我用的树键入对象作为数据源。



    得到这个工作的关键被包裹在一个 ExpandingContainer 对象的数据对象。这个INPC类重要的事情是 IsExpanded 属性(绑定)和儿童的集合:

     公共类ExpandingContainer:INotifyPropertyChanged的{
    公共对象有效载荷{搞定;私人集; }

    公众的ObservableCollection< ExpandingContainer>儿童{搞定;私人集; }

    公共ExpandingContainer(对象的有效载荷){...}

    私人布尔_isexpanded;
    公共BOOL IsExpanded {
    {返回_isexpanded; }
    集合{
    如果(价值== _isexpanded)
    的回报;
    _isexpanded =价值;
    PropertyChanged.Notify(()=> IsExpanded);
    }
    }

    公共事件PropertyChangedEventHandler的PropertyChanged =(O,E)=> {};
    }



    对于XAML,首先让我们得到一些资源出路:

     <! - 绑定ExpandingContainer.IsExpanded到TreeViewItem.IsExpanded  - > 
    <风格的TargetType =树型视图>
    < setter属性=IsExpanded
    值={结合IsExpanded,模式=双向}/>
    < /样式和GT;

    <! - 结合ExpandingContainer.IsExpanded能见度后 - >
    < BooleanToVisibilityConverter X:键=boolvis/>

    <! - 在TreeViewItems应该显示类型的名称 - >
    < HierarchicalDataTemplate数据类型={X:类型LOC:ExpandingContainer}
    X:键=treeViewSide
    的ItemsSource ={结合儿童}>
    < TextBlock的文本={结合Payload.Name}/>
    < / HierarchicalDataTemplate>

    <! - 柱一边是天真单纯,孩子的ItemsControl有必然ExpandingContainer其
    知名度,但列只是$的TextBlocks乙$ B StackPanels - - >
    < HierarchicalDataTemplate数据类型={X:类型LOC:ExpandingContainer}
    X:键=columnSide>
    <&StackPanel的GT;
    < StackPanel.Resources>
    <风格的TargetType =TextBlock的>
    < setter属性=保证金VALUE =10,0/>
    < /样式和GT;
    < /StackPanel.Resources>
    < StackPanel的方向=横向>
    < TextBlock的文本={结合Payload.IsAbstract}/>
    < TextBlock的文本={结合Payload.Namespace}/>
    < TextBlock的文本={结合Payload.GUID}/>
    < / StackPanel的>
    <的ItemsControl的ItemsSource ={结合儿童}
    能见度={结合IsExpanded,转换器= {StaticResource的boolvis}}/>
    < / StackPanel的>
    < / HierarchicalDataTemplate>

    <! - 一种风格不能引用到自身,所以这只是把它应用到所有ItemsControls - >
    <风格的TargetType =ItemsControl的>
    < setter属性=ItemTemplate中
    值={StaticResource的columnSide}/>
    < /样式和GT;



    我最初试图嵌套水平仅的ScrollViewer 内部含有右列垂直仅的ScrollViewer 这是负责的 TreeView控件,但产生的奇怪的规定你不得不滚动至底部水平滚动。于是我进一步把他们分开,放置的ScrollViewer 身边并排。



    要保持垂直滚动条上最右边,我躲在滚动条都围绕 TreeView控件,只使用列周围的滚动条。同步的垂直滚动以完成代码隐藏,但对于更多的MVVM办法做到这一点,你可以把一个附加行为,以促进他们彼此结合。

     <&DockPanel中GT; 
    <的ScrollViewer VerticalScrollBarVisibility =隐藏
    Horizo​​ntalScrollBarVisibility =隐藏
    DockPanel.Dock =左
    NAME =treescroller>
    <树视图的ItemsSource ={绑定表项}
    的ItemTemplate ={StaticResource的treeViewSide}
    填充=0,0,0,20>
    < / TreeView的>
    < /&的ScrollViewer GT;
    <的ScrollViewer NAME =columnscroller
    Horizo​​ntalScrollBarVisibility =自动
    VerticalScrollBarVisibility =自动
    ScrollChanged =columnscroller_ScrollChanged>
    <的ItemsControl的ItemsSource ={绑定表项}/>
    < /&的ScrollViewer GT;
    < / DockPanel中>

    和最后的代码背后的重要位(减去使得数据对象,并设置的DataContext 属性):

     私人无效columnscroller_ScrollChanged(对象发件人,ScrollChangedEventArgs E) {
    treescroller.ScrollToVerticalOffset(columnscroller.VerticalOffset);
    }



    希望它能帮助,或至少提供了不同的视角。



    如果我真的需要一个好一个充满每一个需要我能为混合想到 TreeView控件 + 的ListView ,我可能会看专业控制第一花必要的时间来打磨一个土生土长的解决方案之前。这种事情是更好时,这种显示器的要求很简单。


    I implemented a treeview with columns in WPF using ControlTemplate and a stackpanel of GridViewRowPresenter. I followed this article : http://blogs.msdn.com/b/atc_avalon_team/archive/2006/03/01/541206.aspx

    It works perfectly!

    However, I would like to keep the left column (with the names) visible while scrolling horizontally.

    It would be like 'freeze panes' on microsoft excel on the first column.

    An idea, anyone?

    Thanks Frederic

    解决方案

    The problem with the GridViewRowPresenter solution is that the tree is inextricable from the other columns. I figure you need it to be separate so that you can put the horizontal-only ScrollViewer around the columns, and I doubt this is easy (if possible) to do to the project in the article you linked.

    This project that I slapped together to figure something out is quite rough around the edges. There are a number of issues you would need to work out separately that I didn't fine-tune:

    1. Templates and styling so that lines match up, and other visual tweaks.
    2. Re-introducing the GridView aspects of the linked project for headers and the columns.
    3. A splitter for adjusting the size of the first column (containing the tree).

    Like the article project, I used a tree of Type objects as the data source.

    The crux of getting this to work was wrapping the data objects in an ExpandingContainer object. The important things about this INPC class is the IsExpanded property (for binding) and the collection of children:

    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) => {};
    }
    

    As for the XAML, first let's get some resources out of the way:

    <!-- 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>
    

    I originally tried nesting the horizontal-only ScrollViewer containing the right columns inside the vertical-only ScrollViewer that was responsible for the TreeView, but that produced the strange requirement that you had to scroll to the bottom to scroll horizontally. So I separated them further, placing the ScrollViewers side-by-side.

    To keep the vertical scrollbar on the far right, I hid both scrollbars around the TreeView and use only the scrollbars around the columns. Syncing the vertical scrolling is done in code-behind, but for a more MVVM way to do it, you could make an attached behavior to facilitate binding them to each other.

    <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>
    

    And lastly, the important bit of the code-behind (minus making the data objects and setting the DataContext property):

    private void columnscroller_ScrollChanged( object sender, ScrollChangedEventArgs e ) {
        treescroller.ScrollToVerticalOffset( columnscroller.VerticalOffset );
    }
    

    Hope it helps, or at least provides a different perspective.

    If I really needed a good one that filled every need I could think of for a hybrid TreeView+ListView, I'd probably look at professional controls first before spending the necessary time to polish a home-grown solution. This kind of thing is better when the requirements for such display are simple.

    这篇关于保持一个TreeView的最左列可见,而水平滚动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆