首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >处理可编辑的分层数据/ TreeView~DataGrid混合

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

Stack Overflow用户
提问于 2010-08-11 17:40:09
回答 5查看 18.1K关注 0票数 23

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

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

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2011-03-27 02:01:10

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

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

项目视图模型有一些额外的属性:LevelChildrenIsExpandedIsVisibleLevel是节点祖先的计数,Children包含子视图模型节点,在UI中使用IsExpanded,如果节点可见,则IsVisible为true。它还实现了一个名为VisibleDescendants的属性

代码语言:javascript
复制
public IEnumerable<NodeViewModel> VisibleDescendants
{
   get
   {
      return Children
             .Where(x => x.IsVisible)
             .SelectMany(x => (new[] {x}).Concat(x.VisibleDescendants)));
   }
}

在控件第一列的项的样式中使用LevelHasChildrenIsExpanded:它们控制左边距以及显示的图标类型(如果有)。

您还需要实现ExpandCommandCollapseCommand属性。如果Children.Any()为true且IsExpanded为false,则启用ExpandCommand;如果Children.Any()为true且IsExpanded为true,则启用CollapseCommand。这些命令在执行时会更改IsExpanded的值。

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

代码语言:javascript
复制
public IEnumerable<NodeViewModel> Items
{
   get
   {
      return _Items
             .Where(x => x.IsVisible)
             .SelectMany(x => (new[] {x}).Concat(x.VisibleDescendants));
   }
}

每当任何子体的IsVisible属性发生更改时,父视图模型都会引发Items属性的PropertyChanged,这将强制重新填充数据网格。

还有一个不太简单的实现,您可以使Items属性成为实现INotifyCollectionChanged的类,并且当子节点变为可见/不可见时引发适当的CollectionChanged事件,但您只想在性能有问题的情况下使用它。

票数 14
EN

Stack Overflow用户

发布于 2015-12-13 19:04:01

下面的答案来自@Robert Rossney的答案:

代码语言:javascript
复制
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

代码语言:javascript
复制
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:

代码语言:javascript
复制
<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但相信我,Robert Rossney的想法是一个爆炸:)另外,扩展器'+','-‘样式也包括(注释掉)希望它有帮助:)

票数 7
EN

Stack Overflow用户

发布于 2010-08-11 18:21:49

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3457107

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档