2010-08-11 22 views
19

Tôi đang tìm kiếm một điều khiển WPF đó là một lai của TreeView và DataGrid, một cái gì đó giống như debugger Visual Studio hoặc danh sách địa chỉ liên lạc, vv QuickBooksWPF: Xử lý chỉnh sửa thứ bậc dữ liệu/TreeView ~ DataGrid lai

Bất kỳ giải pháp khác trên cách xử lý dữ liệu phân cấp có thể chỉnh sửa trong WPF cũng sẽ rất được hoan nghênh.

enter image description here

Trả lời

3

chỉ có một cái nhìn tại kiểm soát này

http://www.codeproject.com/KB/WPF/wpf_treelistview_control.aspx

+0

Nhưng tôi muốn kết hợp nó với một DataGrid (có thể chỉnh sửa) – Shimmy

+1

+1 @Shimmy Xem com một phần của http://www.codeproject.com/KB/WPF/wpf_treelistview_control.aspx. nó cho thấy làm thế nào để sử dụng nó với một mạng lưới thay vì một listview – k3b

+0

@ k3b bạn nên đã hướng dẫn này @ Hedge. Tôi nghĩ rằng đây không thực sự là một vấn đề @Shimmy quan tâm đến nữa ... chỉ cần nói ... –

7

Điều này có vẻ với tôi như là một điều hợp lý đơn giản để thực hiện nếu bạn thiết kế mô hình quan điểm của bạn đúng cách.

Bạn về cơ bản thiết kế các mục giống như cách bạn làm nếu hiển thị chúng trong lưới dữ liệu thông thường, tức là mỗi mục có thuộc tính cho mỗi cột. Trong mọi khả năng, mô hình dữ liệu cơ bản của bạn là phân cấp, nhưng bộ sưu tập lưới được ràng buộc sẽ bị phẳng, nghĩa là sẽ chứa một mục cho mỗi nút trong cấu trúc phân cấp không phụ thuộc vào các mối quan hệ cha/con.

Mô hình chế độ xem mục có một số thuộc tính bổ sung: Level, Children, IsExpandedIsVisible. Level là số lượng tổ tiên của nút, Children chứa các nút kiểu xem con, IsExpanded được sử dụng trong giao diện người dùng và IsVisible là đúng nếu nút hiển thị. Nó cũng thực hiện một tính chất gọi là VisibleDescendants:

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

Bạn sử dụng Level, HasChildren, và IsExpanded theo phong cách cho các mục trong cột đầu tiên của kiểm soát: họ kiểm soát lề trái và những loại biểu tượng (nếu có) là hiển thị.

Bạn cũng cần triển khai các thuộc tính ExpandCommandCollapseCommand. ExpandCommand được bật nếu Children.Any() là đúng và IsExpanded là sai và CollapseCommand được bật nếu Children.Any() là đúng và IsExpanded là đúng. Các lệnh này, khi được thực thi, thay đổi giá trị của IsExpanded.

Và đây là nơi thú vị. Cách đơn giản để thực hiện điều này có thể phù hợp với bạn: các mục được hiển thị bởi mô hình chế độ xem gốc có thuộc tính Items không phải là bộ sưu tập. Thay vào đó, nó là một điều tra viên rằng đi xuống chuỗi các mô hình xem đứa trẻ và chỉ có hiệu suất các nút có thể nhìn thấy:

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

Bất cứ khi nào bất kỳ của hậu duệ IsVisible thay đổi sở hữu, quan điểm mô hình mẹ tăng PropertyChanged cho Items bất động sản, trong đó lực lượng dữ liệu lưới để lặp lại. Có một thực hiện đơn giản hơn nữa, nơi bạn làm cho thuộc tính Items một lớp thực hiện INotifyCollectionChanged và tăng các sự kiện thích hợp CollectionChanged khi nút hậu duệ trở nên có thể nhìn thấy/vô hình, nhưng bạn chỉ muốn đến đó nếu hiệu suất là một vấn đề .

+0

Điều này hoạt động awesomely !! – faztp12

2

Câu trả lời sau được phát triển từ câu trả lời của @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); 
     } 
    } 
} 

Lớp trên là những gì ông giải thích. Sử dụng đối tượng Data trong DataGridHierarchialDataModel để đặt trong dữ liệu tùy chỉnh của riêng bạn và tạo dữ liệu phân cấp và đặt nó trong DataGridHierarchialData s RawData. Gọi Initialize khi thực hiện mọi việc;

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; 

^Đây là kịch bản của tôi, vào nhóm Accounts

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> 

Thats Big: P nhưng tôi tin tưởng, ý tưởng Robert Rossney là một vụ nổ :) Ngoài ra, nở ' + ',' - 'Kiểu dáng cũng được bao gồm (đã nhận xét) Hy vọng nó sẽ giúp :)

Các vấn đề liên quan