2010-08-11 346 views

回答

3
+0

但我想混合它與DataGrid(可編輯) – Shimmy 2010-08-11 11:07:27

+1

+1 @Shimmy請參閱com是http://www.codeproject.com/KB/WPF/wpf_treelistview_control.aspx的一部分。它顯示瞭如何使用它,而不是一個列表視圖 – k3b 2011-03-23 14:56:45

+0

@ k3b你應該指示這個@Hedge。我認爲這不是一個真正的問題@Shimmy關心了......只是說... – 2011-03-24 23:07:57

7

這在我看來就像一個相當簡單的事情,如果你正確地設計您的視圖模型來實現。

基本上,設計項目的方式與在正常數據網格中顯示它們時的方式相同,即每個項目對每個列都有一個屬性。很有可能,您的底層數據模型是分層的,但網格綁定的集合將被展平,即不管父/子關係如何,都將包含層次結構中每個節點的項目。

項目視圖模型具有一些額外的屬性:LevelChildrenIsExpanded,並IsVisibleLevel是節點祖先的計數,Children包含子視圖模型節點,在用戶界面中使用IsExpanded,如果節點可見,則IsVisible爲真。它還實現了一個名爲VisibleDescendants屬性:

public IEnumerable<NodeViewModel> VisibleDescendants 
{ 
    get 
    { 
     return Children 
      .Where(x => x.IsVisible) 
      .SelectMany(x => (new[] {x}).Concat(x.VisibleDescendants))); 
    } 
} 

您使用LevelHasChildrenIsExpanded在樣式在控件的第一列的項目:他們所控制的左邊空白,什麼圖標的種類(如果有的話)顯示。

您還需要執行ExpandCommandCollapseCommand屬性。如果Children.Any()爲真且IsExpanded爲假,則啓用ExpandCommand,並且如果Children.Any()爲真並且IsExpanded爲真,則啓用CollapseCommand。這些命令在執行時會更改IsExpanded的值。

這就是它變得有趣的地方。實現此功能的簡單方法可能適用於您:這些項目由父視圖模型公開,該視圖模型的Items屬性不是集合。相反,它是向下傳播子視圖模型的鏈,只產生可見的節點枚舉:

public IEnumerable<NodeViewModel> Items 
{ 
    get 
    { 
     return _Items 
      .Where(x => x.IsVisible) 
      .SelectMany(x => (new[] {x}).Concat(x.VisibleDescendants)); 
    } 
} 

每當任何後代的IsVisible屬性更改,父視圖模型提出了PropertyChangedItems財產,這迫使數據網格重新填充。

有一個不太簡單的實現過,在這裏你做出Items屬性,實現INotifyCollectionChanged一類,而且提高了正確CollectionChanged活動時,子節點成爲可見/不可見,但你只想去那裏,如果性能是一個問題。

+0

這真棒! – faztp12 2015-12-13 09:29:18

2

以下的答案必須從@Robert Rossney的答案開發:

public class DataGridHierarchialDataModel 
{ 

    public DataGridHierarchialDataModel() { Children = new List<DataGridHierarchialDataModel>(); } 


    public DataGridHierarchialDataModel Parent { get; set; } 
    public DataGridHierarchialData DataManager { get; set; } 
    public void AddChild(DataGridHierarchialDataModel t) 
    { 
     t.Parent = this; 
     Children.Add(t); 
    } 


    #region LEVEL 
    private int _level = -1; 
    public int Level 
    { 
     get 
     { 
      if (_level == -1) 
      {      
       _level = (Parent != null) ? Parent.Level + 1 : 0; 
      } 
      return _level; 
     } 
    } 

    #endregion 
    public bool IsExpanded 
    { 
     get { return _expanded; } 
     set 
     { 
      if (_expanded != value) 
      { 
       _expanded = value; 
       if (_expanded == true) 
        Expand(); 
       else 
        Collapse(); 
      } 
     } 
    } 


    public bool IsVisible 
    { 
     get { return _visible; } 
     set 
     { 
      if (_visible != value) 
      { 
       _visible = value; 
       if (_visible) 
        ShowChildren(); 
       else 
        HideChildren(); 
      } 
     } 
    } 
    public bool HasChildren { get { return Children.Count > 0; } } 
    public List<DataGridHierarchialDataModel> Children { get; set; } 



    public object Data { get; set; } // the Data (Specify Binding as such {Binding Data.Field}) 

    public IEnumerable<DataGridHierarchialDataModel> VisibleDescendants 
    { 
     get 
     {    
      return Children 
       .Where(x => x.IsVisible) 
       .SelectMany(x => (new[] {x}).Concat(x.VisibleDescendants));    
     } 
    } 



    // Expand Collapse 
    private bool _expanded = false; 
    private bool _visible = false; 
    private void Collapse() 
    { 
     DataManager.RemoveChildren(this); 
     foreach (DataGridHierarchialDataModel d in Children) 
      d.IsVisible = false; 
    } 

    private void Expand() 
    { 
     DataManager.AddChildren(this); 
     foreach (DataGridHierarchialDataModel d in Children) 
      d.IsVisible = true; 
    } 




    // Only if this is Expanded 
    private void HideChildren() 
    { 
     if (IsExpanded) 
     { 
      // Following Order is Critical 
      DataManager.RemoveChildren(this); 
      foreach (DataGridHierarchialDataModel d in Children) 
       d.IsVisible = false; 
     } 
    } 
    private void ShowChildren() 
    { 
     if (IsExpanded) 
     { 
      // Following Order is Critical 
      DataManager.AddChildren(this); 
      foreach (DataGridHierarchialDataModel d in Children) 
       d.IsVisible = true; 
     } 
    } 
} 

public class DataGridHierarchialData : ObservableCollection<DataGridHierarchialDataModel> 
{ 

    public List<DataGridHierarchialDataModel> RawData { get; set; } 
    public DataGridHierarchialData() { RawData = new List<DataGridHierarchialDataModel>(); } 

    public void Initialize() 
    { 
     this.Clear(); 
     foreach (DataGridHierarchialDataModel m in RawData.Where(c => c.IsVisible).SelectMany(x => new[] { x }.Concat(x.VisibleDescendants))) 
     {     
      this.Add(m); 
     } 
    } 

    public void AddChildren(DataGridHierarchialDataModel d) 
    { 
     if (!this.Contains(d)) 
      return; 
     int parentIndex = this.IndexOf(d); 
     foreach (DataGridHierarchialDataModel c in d.Children) 
     { 
      parentIndex += 1; 
      this.Insert(parentIndex, c); 
     } 
    } 

    public void RemoveChildren(DataGridHierarchialDataModel d) 
    { 
     foreach (DataGridHierarchialDataModel c in d.Children) 
     { 
      if (this.Contains(c)) 
       this.Remove(c); 
     } 
    } 
} 

上面類是什麼他解釋說。 使用DataGridHierarchialDataModel中的Data對象放置您自己的自定義數據,並生成您的等級數據並將其放入DataGridHierarchialDataRawData。萬一完成時致電Initialize;

DataTable accTable = await DB.getDataTable("SELECT * FROM Fm3('l1')"); 
     accTable.DefaultView.Sort = "iParent"; 

     DataGridHierarchialData data = new DataGridHierarchialData(); 

     Action<DataRowView, DataGridHierarchialDataModel> Sort = null; 
     Sort = new Action<DataRowView, DataGridHierarchialDataModel>((row, parent) => 
     { 
      DataGridHierarchialDataModel t = new DataGridHierarchialDataModel() { Data = row, DataManager = data }; 
      if (row["iGroup"].ToString() == "1") 
      {      
       foreach (DataRowView r in accTable.DefaultView.FindRows(row["iSmajId"])) 
        Sort(r, t); 
      } 
      parent.AddChild(t); 
     }); 

     foreach (DataRowView r in accTable.DefaultView.FindRows(0)) 
     { 
      DataGridHierarchialDataModel t = new DataGridHierarchialDataModel() { Data = r, DataManager = data }; 
      if (r["iGroup"].ToString() == "1") 
      {      
       foreach (DataRowView rf in accTable.DefaultView.FindRows(r["iSmajId"])) 
        Sort(rf, t); 
      } 

      t.IsVisible = true; // first layer 
      data.RawData.Add(t); 
     } 
     data.Initialize(); 
     dg.ItemsSource = data; 

^這是我的情況下,以組帳戶

XAML:

<DataGrid x:Name="dg" AutoGenerateColumns="False" IsReadOnly="False" CanUserAddRows="False" GridLinesVisibility="All" ColumnWidth="*"> 

     <DataGrid.Columns> 
      <DataGridTextColumn Header="Name" Binding="{Binding Data.sName}"> 
       <DataGridTextColumn.CellStyle> 
        <Style TargetType="DataGridCell" BasedOn="{StaticResource MetroDataGridCell}"> 
         <Setter Property="Template"> 
          <Setter.Value> 

           <ControlTemplate TargetType="DataGridCell"> 
            <Border BorderBrush="{TemplateBinding BorderBrush}" 
             BorderThickness="{TemplateBinding BorderThickness}" 
             Background="{TemplateBinding Background}" 
             SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"> 

             <StackPanel Orientation="Horizontal"> 
              <ToggleButton x:Name="Expander"            
              Margin="{Binding Level,Converter={StaticResource LevelToIndentConverter}}" 
              IsChecked="{Binding Path=IsExpanded, UpdateSourceTrigger=PropertyChanged}" 
              ClickMode="Press" > 
               <ToggleButton.Style> 
                <Style TargetType="{x:Type ToggleButton}"> 
                 <Setter Property="Focusable" Value="False"/> 
                 <Setter Property="Width" Value="19"/> 
                 <Setter Property="Height" Value="13"/> 
                 <Setter Property="Template"> 
                  <Setter.Value> 
                   <ControlTemplate TargetType="{x:Type ToggleButton}"> 
                    <Border Width="19" Height="13" Background="Transparent"> 
                     <Border Width="9" Height="9" 
                       BorderThickness="0" 
                       BorderBrush="#FF7898B5" 
                       CornerRadius="1" 
                       SnapsToDevicePixels="true"> 
                      <Border.Background> 
                       <SolidColorBrush Color="Transparent"/> 
                       <!-- 
                        <LinearGradientBrush StartPoint="0,0" 
                         EndPoint="1,1"> 
                         <LinearGradientBrush.GradientStops> 
                          <GradientStop Color="White" 
                        Offset=".2"/> 
                          <GradientStop Color="#FFC0B7A6" 
                        Offset="1"/> 
                         </LinearGradientBrush.GradientStops> 
                        </LinearGradientBrush> 
                       --> 
                      </Border.Background> 
                      <Path x:Name="ExpandPath"          
                      Data="M0,0 L0,6 L6,0 z" 
                      Fill="Transparent" 
                      Stroke="{DynamicResource BlackBrush}" Margin="1,2,1,1"> 
                       <Path.RenderTransform> 
                        <RotateTransform Angle="135" 
                        CenterY="3" 
                        CenterX="3" /> 
                       </Path.RenderTransform> 
                      </Path> 
                      <!-- 
                      <Path x:Name="ExpandPath" 
                      Margin="1,1,1,1" 
                      Fill="Black" 
                      Data="M 0 2 L 0 3 L 2 3 L 2 5 L 3 5 L 3 3 L 5 3 L 5 2 L 3 2 L 3 0 L 2 0 L 2 2 Z"/> 
                      --> 
                     </Border> 
                    </Border> 
                    <ControlTemplate.Triggers> 
                     <Trigger Property="IsChecked" 
                      Value="True"> 
                      <Setter Property="RenderTransform" 
                       TargetName="ExpandPath"> 
                       <Setter.Value> 
                        <RotateTransform Angle="180" 
                        CenterY="3" 
                        CenterX="3" /> 
                       </Setter.Value> 
                      </Setter> 
                      <Setter Property="Fill" 
                       TargetName="ExpandPath" 
                       Value="{DynamicResource GrayBrush1}" /> 
                      <Setter Property="Stroke" 
                       TargetName="ExpandPath" 
                       Value="{DynamicResource BlackBrush}" /> 

                       <!-- 
                        <Setter Property="Data" 
                      TargetName="ExpandPath" 
                      Value="M 0 2 L 0 3 L 5 3 L 5 2 Z"/> 
                      --> 
                     </Trigger> 
                    </ControlTemplate.Triggers> 
                   </ControlTemplate> 
                  </Setter.Value> 
                 </Setter> 
                </Style> 
               </ToggleButton.Style> 
              </ToggleButton> 

              <ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}" 
                 Content="{TemplateBinding Content}" 
                 ContentStringFormat="{TemplateBinding ContentStringFormat}" 
                 Margin="{TemplateBinding Padding}" 
                 SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" 
                 VerticalAlignment="{TemplateBinding VerticalContentAlignment}" 
                 HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" /> 


             </StackPanel> 
            </Border> 
            <ControlTemplate.Triggers> 
             <DataTrigger Binding="{Binding HasChildren}" Value="False"> 
              <Setter TargetName="Expander" Property="Visibility" Value="Hidden"/> 
             </DataTrigger> 
            </ControlTemplate.Triggers> 
           </ControlTemplate> 
          </Setter.Value> 
         </Setter> 
        </Style> 
       </DataGridTextColumn.CellStyle> 
      </DataGridTextColumn> 
      <DataGridTextColumn Header="Code" Binding="{Binding Data.sCode}"/> 
      <DataGridTextColumn Header="Type" Binding="{Binding Data.c867x1}"/> 

     </DataGrid.Columns> 
    </DataGrid> 

那大:P,但相信我,羅伯特Rossney的想法是一個爆炸:) 此外,擴展「 +',' - '樣式也包括在內(註釋掉) 希望它有幫助:)