是否可以为 'plain' 集合定义 TreeView 分层视图模板?
Is it possible to define a TreeView hierarchical view template for a 'plain' collection?
我的模型 类 看起来像这样:
class Base
{
public string Name { get; set; }
}
class Item : Base { ... }
class Group : Base
{
public List<Base> GroupItems { get; private set; }
}
然后,我有一个带有 Items
集合的视图模型,我按照下面的 FillUp()
方法所示填充它:
class ViewModel : INotifyPropertyChanged
{
public ObservableCollection<Base> Items { get; set; }
private void FillUp()
{
Item item1 = new Item { Name = "Item1" };
Item item2 = new Item { Name = "Item2" };
Group group = new Group { Name = "Group" };
group.GroupItems.Add(item1);
this.Items.Add(item1);
this.Items.Add(item2);
this.Items.Add(group);
}
}
因此,我的 Items
集合现在包含 2 个 Item
类型的对象和一个 Group
类型的对象,其中 "parent-child" 引用了 Item
对象。
我想要实现的目标:我想在 TreeView
中显示此模型,以便属于某些 Group
的所有 Item
都应显示为子项Group
的元素,尽管它们在 "root" 集合中。
它应该看起来像这样:
- Item2
+ Group
- Item1
我可以使用 HierarchicalDataTemplate
来显示父子元素,但这不允许我从属于某些组的根集合中过滤掉那些项目。
<TreeView>
<TreeView.Resources>
<HierarchicalDataTemplate DataType = "{x:Type loc:Group}" ItemsSource = "{Binding GroupItems}">
<TextBlock Text="{Binding Name}"/>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type loc:Item}">
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</TreeView.Resources>
<TreeViewItem ItemsSource="{Binding Items}"/>
</TreeView>
根据这个视图,我得到了 "Item1"
两次:
- Item1
- Item2
+ Group
- Item1
是否有任何方法可以仅通过视图 (XAML) 标记获得所需的结果?否则,我应该更改我的视图模型,以便 Item
仅添加到 Group
中,而不是添加到 "root" 集合中(但这是我在片刻)。
您可以在您的 ViewModel 中定义两个 Collections,一个用于所有项,一个用于树,看起来很简单。
class ViewModel
{
public ObservableCollection<Base> AllItems { get; set; }
public ObservableCollection<Base> RootLevelItems { get; set; }
}
如果您只有两个级别(例如,没有嵌套组),您可以将 ListView 与 GroupStyle 一起使用。
假设您有一些关于哪个项目属于组的指示,对于此示例,我在组和项目中添加了一个 Guid classes。
您可以通过两种方式解决此问题:
1) 创建复合包装器 class 。
并创建一个 Wrapper class 的 ItemsSource。如果有一个不属于组的单个项目,子项将保持为空。
public class Wrapper<T> where T : Base
{
public List<T> Children { get; set; }
}
public class Base
{
public string Name { get; set; }
}
public class Item : Base
{
public Guid GroupId { get; set; }
}
public class Group : Base
{
public Guid ID { get; set; }
public List<Item> GroupItems { get; private set; }
}
您的第二个选择是使用 CollectionView 并过滤掉属于某个组的项目。
private ICollectionView _baseView;
public ICollectionView BaseView
{
get
{
if (_baseView == null)
{
_baseView = new ListCollectionView((IList) items);
_baseView.Filter = o => o is Group || o is Item && (o as Item).GroupId != Guid.Empty;
}
return _baseView;
}
}
回复您的评论:
There are no duplicates in the collection by the way, as you can see in my code - it's just the view that displays the item twice.
您说您的代码中没有重复项,但显然有:
private void FillUp()
{
Item item1 = new Item { Name = "Item1" };
Item item2 = new Item { Name = "Item2" };
Group group = new Group { Name = "Group" };
group.GroupItems.Add(item1); // Adding item1 into collection in Group
this.Items.Add(item1); // Adding item1 into collection again
this.Items.Add(item2);
this.Items.Add(group);
}
因此,正如我所说,这是预期的行为,而 TreeView
只是向您显示您告诉它的内容。因此,要删除重复项,只需不要将其添加到您的 collection:
private void FillUp()
{
Item item1 = new Item { Name = "Item1" };
Item item2 = new Item { Name = "Item2" };
Group group = new Group { Name = "Group" };
group.GroupItems.Add(item1); // Adding item1 into collection in Group
// this.Items.Add(item1); // Don't add item1 into collection again
this.Items.Add(item2);
this.Items.Add(group);
}
我的模型 类 看起来像这样:
class Base
{
public string Name { get; set; }
}
class Item : Base { ... }
class Group : Base
{
public List<Base> GroupItems { get; private set; }
}
然后,我有一个带有 Items
集合的视图模型,我按照下面的 FillUp()
方法所示填充它:
class ViewModel : INotifyPropertyChanged
{
public ObservableCollection<Base> Items { get; set; }
private void FillUp()
{
Item item1 = new Item { Name = "Item1" };
Item item2 = new Item { Name = "Item2" };
Group group = new Group { Name = "Group" };
group.GroupItems.Add(item1);
this.Items.Add(item1);
this.Items.Add(item2);
this.Items.Add(group);
}
}
因此,我的 Items
集合现在包含 2 个 Item
类型的对象和一个 Group
类型的对象,其中 "parent-child" 引用了 Item
对象。
我想要实现的目标:我想在 TreeView
中显示此模型,以便属于某些 Group
的所有 Item
都应显示为子项Group
的元素,尽管它们在 "root" 集合中。
它应该看起来像这样:
- Item2
+ Group
- Item1
我可以使用 HierarchicalDataTemplate
来显示父子元素,但这不允许我从属于某些组的根集合中过滤掉那些项目。
<TreeView>
<TreeView.Resources>
<HierarchicalDataTemplate DataType = "{x:Type loc:Group}" ItemsSource = "{Binding GroupItems}">
<TextBlock Text="{Binding Name}"/>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type loc:Item}">
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</TreeView.Resources>
<TreeViewItem ItemsSource="{Binding Items}"/>
</TreeView>
根据这个视图,我得到了 "Item1"
两次:
- Item1
- Item2
+ Group
- Item1
是否有任何方法可以仅通过视图 (XAML) 标记获得所需的结果?否则,我应该更改我的视图模型,以便 Item
仅添加到 Group
中,而不是添加到 "root" 集合中(但这是我在片刻)。
您可以在您的 ViewModel 中定义两个 Collections,一个用于所有项,一个用于树,看起来很简单。
class ViewModel
{
public ObservableCollection<Base> AllItems { get; set; }
public ObservableCollection<Base> RootLevelItems { get; set; }
}
如果您只有两个级别(例如,没有嵌套组),您可以将 ListView 与 GroupStyle 一起使用。
假设您有一些关于哪个项目属于组的指示,对于此示例,我在组和项目中添加了一个 Guid classes。
您可以通过两种方式解决此问题:
1) 创建复合包装器 class 。 并创建一个 Wrapper class 的 ItemsSource。如果有一个不属于组的单个项目,子项将保持为空。
public class Wrapper<T> where T : Base
{
public List<T> Children { get; set; }
}
public class Base
{
public string Name { get; set; }
}
public class Item : Base
{
public Guid GroupId { get; set; }
}
public class Group : Base
{
public Guid ID { get; set; }
public List<Item> GroupItems { get; private set; }
}
您的第二个选择是使用 CollectionView 并过滤掉属于某个组的项目。
private ICollectionView _baseView;
public ICollectionView BaseView
{
get
{
if (_baseView == null)
{
_baseView = new ListCollectionView((IList) items);
_baseView.Filter = o => o is Group || o is Item && (o as Item).GroupId != Guid.Empty;
}
return _baseView;
}
}
回复您的评论:
There are no duplicates in the collection by the way, as you can see in my code - it's just the view that displays the item twice.
您说您的代码中没有重复项,但显然有:
private void FillUp()
{
Item item1 = new Item { Name = "Item1" };
Item item2 = new Item { Name = "Item2" };
Group group = new Group { Name = "Group" };
group.GroupItems.Add(item1); // Adding item1 into collection in Group
this.Items.Add(item1); // Adding item1 into collection again
this.Items.Add(item2);
this.Items.Add(group);
}
因此,正如我所说,这是预期的行为,而 TreeView
只是向您显示您告诉它的内容。因此,要删除重复项,只需不要将其添加到您的 collection:
private void FillUp()
{
Item item1 = new Item { Name = "Item1" };
Item item2 = new Item { Name = "Item2" };
Group group = new Group { Name = "Group" };
group.GroupItems.Add(item1); // Adding item1 into collection in Group
// this.Items.Add(item1); // Don't add item1 into collection again
this.Items.Add(item2);
this.Items.Add(group);
}