2011-04-07 94 views
21

我使用ControlTemplate和GridViewRowPresenter的堆棧面板實現了WPF中的列的樹狀視圖。我跟着這篇文章:http://blogs.msdn.com/b/atc_avalon_team/archive/2006/03/01/541206.aspx在水平滾動時保持樹形視圖的最左側列可見

它完美的作品!

但是,我想保持左側列(與名稱)水平滾動時可見。

這就像在第一列微軟excel上的「凍結窗格」。

一個想法,任何人?

感謝 弗雷德裏克

+4

它可以通過將ScrollViewer僅應用於右側的列,然後將一個不可見的scrollviewer應用到左列並綁定垂直位置來實現。但是需要很多時間來整理代碼。 – vorrtex 2011-04-07 22:26:51

+0

不是你想要的答案,但是當我看到你的問題並且可以確認他們的WPF TreeList完全符合你的想法時,我碰巧正在使用DevExpress的WPF演示。實際上,您可以在左側或右側修復任意數量的列。即使應付列分類。 – 2011-05-21 06:56:04

回答

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

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

我最初試圖在只包含垂直ScrollViewer的垂直水平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> 

最後,代碼隱藏(減去使得數據對象和設置DataContext屬性)的重要的一點:

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

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

如果我真的需要一個好一個充滿每一個需要我可以爲混合TreeView + ListView想,我可能會看專業控制第一個花費必要的時間來打磨一個土生土長的解決方案之前。當這種顯示的要求很簡單時,這種事情會更好。

+0

+1:你的回答留下了很多想象,包括語法錯誤(例如'Setter Property =「Margin」'),並且有你的限制。儘管如此,我得到了它的工作,它確實證明了解決問題的可行方法。偉大的工作,你真的贏得了這個獎金! – 2011-05-27 01:07:41

+0

修復了Setter。有些事情因時間的緣故而被忽略,有些是因爲它們不相關。除了正確地做專欄(週末可能會這樣做),有沒有什麼您認爲需要添加或以其他方式留在想象中的? – 2011-05-27 02:03:42

+0

提供一個簡潔和可消費的答案總是很難,這個問題使它倍增。任何**需要**這個問題的答案都會在你的答案中變成粉紅色。但是,既然我放棄了這些賞金點,我對我的讚美加了一點批評。在未來的問題上繼續做好工作! – 2011-05-27 02:12:36

2

難道是值得的安排行的另一StackPanel的左側,然後以某種方式在左側面板中的數據綁定到右面板的第一列?然後,您可以隱藏右側面板的第一列。左側面板的尺寸可以適當調整而不需要水平滾動,右側面板可以進行普通的水平滾動。

我會想象左側面板的垂直滾動將不得不被綁定到右側面板的垂直滾動。

只是一個想法;希望你能找到更好的辦法。

相關問題