WPF TreeView - 来自VM中FLAT LIST的TreeViewItem源过滤

时间:2014-01-20 12:26:02

标签: wpf treeview treeviewitem

我有一个使用TreeView的简单应用程序,我想显示一个SHAPES层次结构。我正在使用MVVM,所以我有一个ViewModel,它具有ObservableCollection Shapes的属性。

ShapeVm是基类,有几种Shape子类型(SquareVm,CircleVm,ArcVm等)。很基本的东西。 ShapeVm基类具有一个名为ShapeType的overidable属性(枚举:enum {Square,Circle,Arc},每个ShapeVm子类提供它的Shape类型。

现在,你可以看到它的发展方向:在TreeView中,我需要的是这些形状的分层显示,带有'ShapeType'节点,每个节点都包含该类型的形状。

所以,我已经在XAML中尝试了各种各样的东西,比如CollectionViewSource,它提供了一种按ShapeType分组的方法,它可以工作,但它只显示列表中存在的项目和组。

在TreeView中,我需要显示那些组节点,无论它们是否有项目。

所以,例如(Windows的DataContext绑定到ShapesViewModel,它具有'Shapes'属性)

<TreeView>

<!-- Itemtemplate omitted here -->

  <TreeViewItem Header="Rectangles" IsExpanded="true" ItemsSource="{Binding Shapes}">
  </TreeViewItem>

  <TreeViewItem Header="Squares" IsExpanded="true" ItemsSource="{Binding Shapes}">
  </TreeViewItem>

  <TreeViewItem Header="Circles" IsExpanded="true" ItemsSource="{Binding Shapes}">
  </TreeViewItem>

</TreeView>

现在,我摆弄了我的ViewModel,在那里我展示了每个Type类型的属性,一个集合,它从主要的形状集合中获取数据。我知道ViewModels的工作应该在那里“提供”View,无论View需要做什么工作。但是我不想拥有一大堆公共Collection类型,每个类型都需要在每次更改时以某种方式与主Shapes集合“同步”。它变得复杂。

我只是想知道在XAML中是否有办法说:“嘿,'矩形'节点,你必须只显示'矩形',来自Shapes集合,好吧。”

帮助表示赞赏。

1 个答案:

答案 0 :(得分:0)

我不确定XAML是否可以限制每个子部分中的类型,但一种解决方案是从Shapes枚举的外部LINQ连接中获取数据。

下面的类包含Shapes with ShapeTypes和一个枚举,ShapesData属性公开了一个LINQ外连接,可以使用下面的xaml显示。

此解决方案将为您提供空组,其中不存在具有该ShapeType的项目,并且可以轻松应用于TreeView解决方案。

public class FixedTypes
    {
        public enum ShapeType
        {
            Circle,
            Ellipse,
            Rectangle
        }

        public class Shape
        {
            public ShapeType ShapeType { get; set; }
        }

        public ObservableCollection<Shape> Shapes { get; set; }

        public FixedTypes()
        {
            this.Shapes =
                new ObservableCollection<Shape>(
                    new[]
                        {
                            new Shape() { ShapeType = ShapeType.Circle }, new Shape() { ShapeType = ShapeType.Ellipse },
                            new Shape() { ShapeType = ShapeType.Ellipse }
                        });
        }

        public IEnumerable ShapesData
        {
            get
            {
                var data = from e in (ShapeType[])Enum.GetValues(typeof(ShapeType))
                           join s in Shapes on e equals s.ShapeType into es
                           from s in es.DefaultIfEmpty()
                           select new { ShapeType = e, Shape = s};
                return data;
            }
        }
    }

XAML

<Grid>
        <Grid.Resources>
            <CollectionViewSource x:Key="fixedTypes"
                                  Source="{Binding ShapesData}">
                <CollectionViewSource.GroupDescriptions>
                    <PropertyGroupDescription PropertyName="ShapeType" />
                </CollectionViewSource.GroupDescriptions>
            </CollectionViewSource>
        </Grid.Resources>

        <ItemsControl ItemsSource="{Binding Source={StaticResource fixedTypes}}">
            <ItemsControl.GroupStyle>
                <GroupStyle>
                    <GroupStyle.ContainerStyle>
                        <Style TargetType="{x:Type GroupItem}">
                            <Setter Property="Template">
                                <Setter.Value>
                                    <ControlTemplate TargetType="{x:Type GroupItem}">
                                        <GroupBox Header="{Binding Name}">
                                            <ItemsPresenter />
                                        </GroupBox>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                        </Style>
                    </GroupStyle.ContainerStyle>
                </GroupStyle>
            </ItemsControl.GroupStyle>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Shape.ShapeType}" />
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Grid>