WPF:处理可编辑的分层数据/ TreeView~DataGrid混合

时间:2022-05-17 17:01:18

I am looking for a WPF control which is a hybrid of TreeView and DataGrid, something like the Visual Studio debugger or QuickBooks contacts list etc.

我正在寻找一个WPF控件,它是TreeView和DataGrid的混合,类似于Visual Studio调试器或QuickBooks联系人列表等。

Any other solution on how to handle editable hierarchical data in WPF will be very welcommed as well.

关于如何在WPF中处理可编辑的层次化数据的任何其他解决方案也将非常受欢迎。

WPF:处理可编辑的分层数据/ TreeView~DataGrid混合

4 个解决方案

#1


2  

just have a look at this control

看看这个控件

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

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

#2


9  

This seems to me like a reasonably straightforward thing to implement if you design your view model properly.

如果您正确地设计视图模型,那么在我看来,这似乎是一件相当简单的事情。

You basically design the items the same way you would if displaying them in a normal data grid, i.e. each item has a property for each column. In all likelihood, your underlying data model is hierarchical, but the collection that the grid is bound to is going to be flattened, i.e. will contain an item for each node in the hierarchy irrespective of parent/child relationships.

基本上,设计条目的方式与在普通数据网格中显示条目的方式相同,也就是说,每个条目对每个列都有一个属性。在所有可能的情况下,您的底层数据模型是分层的,但是网格绑定到的集合是扁平的,也就是说,不管父/子关系如何,都将包含层次结构中每个节点的一个项。

The item view model has some additional properties: Level, Children, IsExpanded, and IsVisible. Level is a count of the node's ancestors, Children contains the child view model nodes, IsExpanded is used in the UI, and IsVisible is true if the node is visible. It also implements a property called VisibleDescendants:

项目视图模型有一些附加属性:Level、Children、IsExpanded和IsVisible。Level是节点祖先的计数,子节点包含子视图模型节点,IsExpanded用于UI,如果节点可见,IsVisible就是true。它还实现了一个名为visibledescent的属性:

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

You use Level, HasChildren, and IsExpanded in the style for the item in the control's first column: they control the left margin and what kind of icon (if any) is displayed.

您可以使用Level、HasChildren和IsExpanded作为控件第一列中项目的样式:它们控制左页边距以及显示何种图标(如果有的话)。

You also need to implement ExpandCommand and CollapseCommand properties. The ExpandCommand is enabled if Children.Any() is true and IsExpanded is false, and the CollapseCommand is enabled if Children.Any() is true and IsExpanded is true. These commands, when executed, change the value of IsExpanded.

您还需要实现ExpandCommand和secommand属性。任何()都是真实的,而IsExpanded是假的,并且如果孩子们有了崩溃的命令。任何()都是正确的,并且IsExpanded是正确的。执行这些命令时,将更改IsExpanded的值。

And here's where it gets interesting. The simple way to implement this may work for you: the items are exposed by a parent view model whose Items property is not a collection. Instead, it's an enumerator that travels down the chain of child view models and yields only the visible nodes:

这就是有趣的地方。实现这一点的简单方法可能对您有用:项由父视图模型公开,父视图模型的items属性不是集合。相反,它是一个遍历子视图模型链并只产生可见节点的枚举器:

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

Whenever any descendant's IsVisible property changes, the parent view model raises PropertyChanged for the Items property, which forces the data grid to repopulate.

每当任何后代的IsVisible属性发生更改时,父视图模型都会为Items属性引发PropertyChanged,从而迫使数据网格重新填充。

There's a less simple implementation too, where you make the Items property a class that implements INotifyCollectionChanged, and that raises the proper CollectionChanged events when descendant nodes become visible/invisible, but you only want to go there if performance is an issue.

还有一种不那么简单的实现,即将Items属性设置为实现INotifyCollectionChanged的类,并在后代节点变得可见/不可见时引发适当的集合更改事件,但您只希望在性能有问题时访问它。

#3


4  

Following answer is developed from @Robert Rossney's answer:

以下是@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);
        }
    }
}

The above class is what he explained. Use the Data object in the DataGridHierarchialDataModel to place in your own custom data, and generate your hierarchial data and place it in DataGridHierarchialDatas RawData. Call Initialize when everythings done;

上面的课就是他解释的。使用datagridhieraldatamodel中的数据对象来放置自己的自定义数据,并生成分层数据并将其放置到datagridhieraldatas RawData中。当所有事情完成时调用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;

^ This was my scenario, to group Accounts

^这是我的情况下,集团账户

XAML :

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 but trust me, Robert Rossney's idea is a blast :) Also, expander '+', '-' Styles are also included (commented out) Hope it helps :)

这很重要:P但是相信我,罗伯特·罗斯尼的想法非常棒:)此外,扩展器'+' -'风格也包括在内(注释)希望它能有所帮助:

#4


0  

I've found that the best MVVM approach is possible with this control: http://blogs.msdn.com/b/atc_avalon_team/archive/2006/03/01/541206.aspx

我发现最好的MVVM方法可能是使用这个控件:http://blogs.msdn.com/b/atc_avalon_team/archive/2006/03/01/541206.aspx

To use it with hierarchical view models, you can use hierarchical data template and view model guide from here: http://www.codeproject.com/Articles/24973/TreeListView

要在分层视图模型中使用它,可以使用分层数据模板和视图模型指南:http://www.codeproject.com/Articles/24973/TreeListView

#1


2  

just have a look at this control

看看这个控件

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

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

#2


9  

This seems to me like a reasonably straightforward thing to implement if you design your view model properly.

如果您正确地设计视图模型,那么在我看来,这似乎是一件相当简单的事情。

You basically design the items the same way you would if displaying them in a normal data grid, i.e. each item has a property for each column. In all likelihood, your underlying data model is hierarchical, but the collection that the grid is bound to is going to be flattened, i.e. will contain an item for each node in the hierarchy irrespective of parent/child relationships.

基本上,设计条目的方式与在普通数据网格中显示条目的方式相同,也就是说,每个条目对每个列都有一个属性。在所有可能的情况下,您的底层数据模型是分层的,但是网格绑定到的集合是扁平的,也就是说,不管父/子关系如何,都将包含层次结构中每个节点的一个项。

The item view model has some additional properties: Level, Children, IsExpanded, and IsVisible. Level is a count of the node's ancestors, Children contains the child view model nodes, IsExpanded is used in the UI, and IsVisible is true if the node is visible. It also implements a property called VisibleDescendants:

项目视图模型有一些附加属性:Level、Children、IsExpanded和IsVisible。Level是节点祖先的计数,子节点包含子视图模型节点,IsExpanded用于UI,如果节点可见,IsVisible就是true。它还实现了一个名为visibledescent的属性:

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

You use Level, HasChildren, and IsExpanded in the style for the item in the control's first column: they control the left margin and what kind of icon (if any) is displayed.

您可以使用Level、HasChildren和IsExpanded作为控件第一列中项目的样式:它们控制左页边距以及显示何种图标(如果有的话)。

You also need to implement ExpandCommand and CollapseCommand properties. The ExpandCommand is enabled if Children.Any() is true and IsExpanded is false, and the CollapseCommand is enabled if Children.Any() is true and IsExpanded is true. These commands, when executed, change the value of IsExpanded.

您还需要实现ExpandCommand和secommand属性。任何()都是真实的,而IsExpanded是假的,并且如果孩子们有了崩溃的命令。任何()都是正确的,并且IsExpanded是正确的。执行这些命令时,将更改IsExpanded的值。

And here's where it gets interesting. The simple way to implement this may work for you: the items are exposed by a parent view model whose Items property is not a collection. Instead, it's an enumerator that travels down the chain of child view models and yields only the visible nodes:

这就是有趣的地方。实现这一点的简单方法可能对您有用:项由父视图模型公开,父视图模型的items属性不是集合。相反,它是一个遍历子视图模型链并只产生可见节点的枚举器:

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

Whenever any descendant's IsVisible property changes, the parent view model raises PropertyChanged for the Items property, which forces the data grid to repopulate.

每当任何后代的IsVisible属性发生更改时,父视图模型都会为Items属性引发PropertyChanged,从而迫使数据网格重新填充。

There's a less simple implementation too, where you make the Items property a class that implements INotifyCollectionChanged, and that raises the proper CollectionChanged events when descendant nodes become visible/invisible, but you only want to go there if performance is an issue.

还有一种不那么简单的实现,即将Items属性设置为实现INotifyCollectionChanged的类,并在后代节点变得可见/不可见时引发适当的集合更改事件,但您只希望在性能有问题时访问它。

#3


4  

Following answer is developed from @Robert Rossney's answer:

以下是@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);
        }
    }
}

The above class is what he explained. Use the Data object in the DataGridHierarchialDataModel to place in your own custom data, and generate your hierarchial data and place it in DataGridHierarchialDatas RawData. Call Initialize when everythings done;

上面的课就是他解释的。使用datagridhieraldatamodel中的数据对象来放置自己的自定义数据,并生成分层数据并将其放置到datagridhieraldatas RawData中。当所有事情完成时调用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;

^ This was my scenario, to group Accounts

^这是我的情况下,集团账户

XAML :

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 but trust me, Robert Rossney's idea is a blast :) Also, expander '+', '-' Styles are also included (commented out) Hope it helps :)

这很重要:P但是相信我,罗伯特·罗斯尼的想法非常棒:)此外,扩展器'+' -'风格也包括在内(注释)希望它能有所帮助:

#4


0  

I've found that the best MVVM approach is possible with this control: http://blogs.msdn.com/b/atc_avalon_team/archive/2006/03/01/541206.aspx

我发现最好的MVVM方法可能是使用这个控件:http://blogs.msdn.com/b/atc_avalon_team/archive/2006/03/01/541206.aspx

To use it with hierarchical view models, you can use hierarchical data template and view model guide from here: http://www.codeproject.com/Articles/24973/TreeListView

要在分层视图模型中使用它,可以使用分层数据模板和视图模型指南:http://www.codeproject.com/Articles/24973/TreeListView