2010-08-11 17 views

risposta

3

Basta dare uno sguardo a questo controllo

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

+0

Ma io voglio ibridarlo con un DataGrid (modificabile) – Shimmy

+1

+1 @Shimmy Vedi com parte di http://www.codeproject.com/KB/WPF/wpf_treelistview_control.aspx. mostra come usarlo con una griglia invece di una listview – k3b

+0

@ k3b dovresti aver diretto questo @Hedge. Penso che questo non sia davvero un problema a cui @Shimmy si preoccupa più ... semplicemente dicendo ... –

7

Questa mi sembra una cosa abbastanza semplice da implementare, se si progetta il tuo modello di vista in modo corretto.

Fondamentalmente si progettano gli elementi nello stesso modo in cui si visualizzeranno in una normale griglia di dati, vale a dire che ogni articolo ha una proprietà per ogni colonna. Con ogni probabilità, il modello di dati sottostante è gerarchico, ma la raccolta alla quale la griglia è vincolata verrà appiattita, cioè conterrà un elemento per ciascun nodo nella gerarchia, indipendentemente dalle relazioni padre/figlio.

L'articolo vista del modello ha alcune proprietà aggiuntive: Level, Children, IsExpanded e IsVisible. Level è un conteggio degli antenati del nodo, Children contiene i nodi del modello di visualizzazione figlio, IsExpanded viene utilizzato nell'interfaccia utente e IsVisible è true se il nodo è visibile. Implementa anche una proprietà chiamata VisibleDescendants:

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

Si utilizza Level, HasChildren, e IsExpanded nello stile per la voce nella prima colonna del controllo: essi controllano il margine sinistro e che tipo di icona (se presente) è visualizzato.

È inoltre necessario implementare le proprietà ExpandCommand e CollapseCommand. Il ExpandCommand è abilitato se Children.Any() è vero e IsExpanded è falso e CollapseCommand è abilitato se Children.Any() è vero e IsExpanded è vero. Questi comandi, una volta eseguiti, modificano il valore di IsExpanded.

Ed ecco dove diventa interessante. Il modo semplice per implementare questo può funzionare per te: gli oggetti sono esposti da un modello di visualizzazione genitore la cui proprietà Items non è una collezione. Invece, è un enumeratore che viaggia lungo la catena di vista figlio modelli e produce solo i nodi visibili:

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

Ogni volta IsVisible modifiche alle proprietà di qualsiasi discendenti, la vista del modello genitore solleva PropertyChanged per la proprietà Items, che costringe i dati griglia da ripopolare.

C'è un meno semplice implementazione troppo, in cui si effettua la Items proprietà una classe che implementa INotifyCollectionChanged, e che solleva la corretta CollectionChanged eventi quando nodi discendenti diventano visibili/invisibili, ma si vuole solo andare lì se le prestazioni sono un problema .

+0

Questo funziona incredibilmente !! – faztp12

2

risposta In seguito è stato sviluppato dalla risposta di @ 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); 
     } 
    } 
} 

La classe di cui sopra è quello che ha spiegato. Utilizzare l'oggetto Data nello DataGridHierarchialDataModel per inserire i propri dati personalizzati e generare i propri dati gerarchici e posizionarli in DataGridHierarchialData s RawData. Chiama il numero Initialize quando tutto è fatto;

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; 

^Questo era il mio scenario, al gruppo Account

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> 

Quello è grande: P ma credetemi, l'idea di Robert Rossney è uno scoppio :) Inoltre, expander ' + ',' - 'Anche gli stili sono inclusi (commentato) Spero che aiuti :)