代码之家  ›  专栏  ›  技术社区  ›  Shimmy Weitzhandler 500 - Internal Server Error

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

  •  21
  • Shimmy Weitzhandler 500 - Internal Server Error  · 技术社区  · 14 年前

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

    enter image description here

    4 回复  |  直到 5 年前
        1
  •  14
  •   Robert Rossney    13 年前

    基本上,设计项的方式与在普通数据网格中显示项的方式相同,即每个项的每一列都有一个属性。很可能,您的基础数据模型是层次结构的,但是网格绑定到的集合将被展平,即,对于层次结构中的每个节点都将包含一个项,而不管父/子关系如何。

    项目视图模型具有一些附加属性: Level , Children IsExpanded ,和 IsVisible 水平 是节点的祖先的计数, 儿童 I扩展 在UI中使用,并且 可见 VisibleDescendants :

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

    你用 水平 HasChildren ,和 I扩展 在控件的第一列中的项的样式中:它们控制左边距以及显示什么样的图标(如果有的话)。

    你还需要实施 ExpandCommand CollapseCommand 属性。这个 启用的条件是 Children.Any() 是真实的 I扩展 是假的 CollapseCommand命令 启用的条件是 Children.Any() 是真实的 I扩展 这是真的。这些命令在执行时会更改 .

    这就是有趣的地方。实现这一点的简单方法可能适用于您:项由父视图模型公开,父视图模型的 Items

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

    任何后代的 可见 PropertyChanged 对于 项目 属性,强制数据网格重新填充。

    还有一个不那么简单的实现,在这里您可以 属性实现的类 INotifyCollectionChanged ,这就提高了 CollectionChanged

        2
  •  6
  •   fahimalizain    9 年前

    以下答案由@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);
            }
        }
    }
    

    上面的课是他解释的。 使用 Data 中的对象 DataGridHierarchialDataModel DataGridHierarchialData 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;
    

    ^这是我的设想,对客户进行分组

    <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但是相信我,罗伯特·罗斯尼的想法是个爆炸:) 此外,还包括扩展“+”、“-”样式(注释掉)

        5
  •  0
  •   David Invenio    5 年前

    很晚才来参加这个聚会,但据说这个帖子在两个月前还很活跃。我不知道这些评论是怎么写的,因为没有一个是最近才发表的,但我还是会提供这个,因为我刚刚找到了它,并且想分享答案,以防其他人也在寻找它。

    我在CodeProject上找到了这个-它被包装在一个漂亮整洁的小包裹里。到目前为止,似乎工作完美(ps:这怎么已经不是正常的WPF了?我可以在WinForms中使用任意数量的控件自动完成)

    以下是链接-希望对您有所帮助: https://www.codeproject.com/Articles/1213466/WPF-TreeGrid-using-a-DataGrid